假设我们有 2 个线程,线程 A 和线程 B。
线程 A 是 main 方法,包含大型数据结构。
是否可以创建第二个线程并将数据结构(线程 A 本地)的地址(指针)传递给线程 B,以便两个线程都可以从数据结构中读取?
这样做的目的是避免需要在线程 B 上复制整个数据结构或花费大量时间从数据结构中提取相关信息以供线程 B 使用
请记住,两个线程都没有修改数据
假设我们有 2 个线程,线程 A 和线程 B。
线程 A 是 main 方法,包含大型数据结构。
是否可以创建第二个线程并将数据结构(线程 A 本地)的地址(指针)传递给线程 B,以便两个线程都可以从数据结构中读取?
这样做的目的是避免需要在线程 B 上复制整个数据结构或花费大量时间从数据结构中提取相关信息以供线程 B 使用
请记住,两个线程都没有修改数据
它在 java 中被称为引用,因为您无法直接访问传统意义上的指针。(在大多数情况下,将其视为“安全”,因为每个引用都是一个始终按值传递的指针,唯一合法的操作是取消引用它。它与 C ++的“引用”不同。)
您当然可以在线程之间共享引用。任何可以获得对它的引用的线程都可以看到和使用堆上的任何内容。您可以将其放在静态位置,也可以将引用的值设置Runnable
为指向数据。
public class SharedDataTest {
private static class SomeWork implements Runnable {
private Map<String, String> dataTable;
public SomeWork(Map<String, String> dataTable) {
this.dataTable = dataTable;
}
@Override
public void run() {
//do some stuff with dataTable
}
}
public static void main(String[] args) {
Map<String, String> dataTable = new ConcurrentHashMap<String, String>();
Runnable work1 = new SomeWork(dataTable);
Runnable work2 = new SomeWork(dataTable);
new Thread(work1).start();
new Thread(work2).start();
}
}
是的,这是可能的,而且是通常的做法,但您需要确保使用正确的同步来确保两个线程都能看到最新版本的数据。
共享对不可变对象的引用是安全的。粗略地说,不可变对象是构造后状态不变的对象。语义上不可变对象应仅包含最终字段,而这些字段又引用不可变对象。
如果要共享对可变对象的引用,则需要使用适当的同步,例如使用 synchronized 或 volatile 关键字。
安全共享数据的简单方法是使用 java.util.concurrent 包中的实用程序,例如AtomicReference或 ConcurrentHashMap,但是如果您共享的对象是可变的,您仍然必须非常小心。
如果您没有对共享数据进行任何修改,您可以拥有一个共享引用,并且不会产生重大开销。
但是,当您开始同时修改共享对象时要小心,在这种情况下,您可以使用 java 中提供的数据结构(参见示例工厂方法Collections
),或使用自定义同步方案,例如 with java.util.concurrent.locks.ReentrantLock
。