在 Java 中,父子线程之间共享数据并不是直接支持的特性,需要通过特定的机制来实现。
以下是常见的方式及其原理。
1. 自定义传递机制
父线程在创建子线程时,可以通过构造函数或成员变量将需要共享的数据显式传递给子线程。
示例代码:
class MyThread extends Thread {
private String sharedData;
public MyThread(String sharedData) {
this.sharedData = sharedData;
}
@Override
public void run() {
System.out.println("Shared data in child thread: " + sharedData);
}
}
public class Main {
public static void main(String[] args) {
String data = "Hello from parent thread";
MyThread childThread = new MyThread(data);
childThread.start();
}
}
注意事项:
需要显式传递数据,不够灵活。如果数据是可变的,需要考虑线程安全问题。
2. 使用 InheritableThreadLocal
InheritableThreadLocal
是 ThreadLocal
的增强版,允许子线程继承父线程的 ThreadLocal
数据。
示例代码:
public class Main {
private static final InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("Parent data");
Thread childThread = new Thread(() -> {
System.out.println("Data in child thread: " + threadLocal.get());
threadLocal.set("Child data");
System.out.println("Updated data in child thread: " + threadLocal.get());
});
childThread.start();
System.out.println("Data in parent thread: " + threadLocal.get());
}
}
输出结果:
Data in child thread: Parent data
Updated data in child thread: Child data
Data in parent thread: Parent data
原理:
子线程在创建时,会调用 Thread
构造方法中的 init
方法。
如果父线程有 InheritableThreadLocal
数据,子线程会复制这些数据。
局限性:
适用于显式创建的线程(通过 new Thread
)。
对线程池或线程复用无效。
3. 使用 TransmittableThreadLocal
TransmittableThreadLocal
是阿里巴巴开源的工具类,增强了 InheritableThreadLocal
,支持在线程池和线程复用场景下传递数据。
示例代码:
import com.alibaba.ttl.TransmittableThreadLocal;
public class Main {
private static final TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
threadLocal.set("Parent data");
Thread childThread = new Thread(() -> {
System.out.println("Data in child thread: " + threadLocal.get());
});
childThread.start();
childThread.join();
System.out.println("Data in parent thread: " + threadLocal.get());
}
}
优势:
解决了 InheritableThreadLocal
在线程池复用场景下数据无法传递的问题。自动传递数据到线程池内的线程中。
4. 使用共享数据结构
父子线程可以通过共享的线程安全数据结构(如 ConcurrentHashMap
、BlockingQueue
)实现数据共享。
示例代码:
import java.util.concurrent.ConcurrentHashMap;
public class Main {
private static final ConcurrentHashMap<Long, String> sharedMap = new ConcurrentHashMap<>();
public static void main(String[] args) {
sharedMap.put(Thread.currentThread().getId(), "Parent data");
Thread childThread = new Thread(() -> {
String data = sharedMap.get(Thread.currentThread().getId());
System.out.println("Data in child thread: " + data);
});
childThread.start();
}
}
优势:
不依赖线程创建方式,灵活,适合复杂的数据共享需求。
适用场景
总结
父子线程之间共享或传递数据可以通过多种方式实现,选择方式需根据场景和需求决定。
InheritableThreadLocal
和 TransmittableThreadLocal
是较为优雅的解决方案,而共享数据结构则更灵活但更复杂。