【发布时间】:2015-12-31 06:58:46
【问题描述】:
我对在 Java 中的线程之间安全共享数组感到困惑,特别是内存栅栏和关键字 synchronized。
此问答很有帮助,但并未回答我的所有问题:Java arrays: synchronized + Atomic*, or synchronized suffices?
以下是演示该问题的示例代码。假设有一个工作线程池通过方法add(...) 填充SharedTable。在所有工作线程完成后,最后一个线程读取并保存数据。
演示问题的示例代码:
public final class SharedTable {
// Column-oriented data entries
private final String[] data1Arr;
private final int[] data2Arr;
private final long[] data3Arr;
private final AtomicInteger nextIndex;
public SharedTable(int size) {
this.data1Arr = new String[size];
this.data2Arr = new int[size];
this.data3Arr = new long[size];
this.nextIndex = new AtomicInteger(0);
}
// Thread-safe: Called by worker threads
public void addEntry(String data1, int data2, long data3) {
final int index = nextIndex.getAndIncrement();
data1Arr[index] = data1;
data2Arr[index] = data2;
data3Arr[index] = data3;
}
// Not thread-safe: Called by clean-up/joiner/collator thread...
// after worker threads are complete
public void save() {
// Does this induce a full memory fence to ensure thread-safe reading of
synchronized (this) {
final int usedSide = nextIndex.get();
for (int i = 0; i < usedSide; ++i) {
final String data1 = data1Arr[i];
final int data2 = data2Arr[i];
final long data3 = data3Arr[i];
// TODO: Save data here
}
}
}
}
上面的示例代码也可以使用Atomic*Array 来实现,它充当“可变值/引用数组”。
public final class SharedTable2 {
// Column-oriented data entries
private final AtomicReferenceArray<String> data1Arr;
private final AtomicIntegerArray data2Arr;
private final AtomicLongArray data3Arr;
private final AtomicInteger nextIndex;
public SharedTable2(int size) { ... }
// Thread-safe: Called by worker threads
public void addEntry(String data1, int data2, long data3) {
final int index = nextIndex.getAndIncrement();
data1Arr.set(index, data1);
...
}
// Not thread-safe: Called by clean-up/joiner/collator thread...
// after worker threads are complete
public void save() {
final int usedSide = nextIndex.get();
for (int i = 0; i < usedSide; ++i) {
final String data1 = data1Arr.get(i);
final int data2 = data2Arr.get(i);
final long data3 = data3Arr.get(i);
// TODO: Save data here
}
}
}
-
SharedTable线程安全(并且缓存一致)吗? -
SharedTable(很多?)效率更高,因为只需要一个内存栅栏,而SharedTable2每次调用Atomic*Array.set(...)都会调用一个内存栅栏?
如果有帮助,我将在 64 位 x86 硬件(Windows 和 Linux)上使用 Java 8。
【问题讨论】:
-
SharedTable和SharedTable2中方法public void addEntry(..)上方的注释说此方法是线程安全的。我假设您在调用public void addEntry(..)方法时可能正在同步工作线程中的SharedTable或SharedTable2对象。不是吗?
标签: java arrays multithreading volatile memory-fences