我坚持以下情况:
使用未设置引用(n
)的大小为null
的数组实例化新对象。
构建步骤应该为每个索引分配一次引用,然后返回完全填充的数组。
复杂性是阵列由多个线程并行提供。
我不关心set操作的原子性,因为两个线程无法访问同一个索引,但是,我想确保返回填充数组的线程“看到”每个填充的索引。 / p>
private final String[] arr = new String[n];
private void parallelFeed() {...} // Multi-threaded
public void build() {
parallelFeed(arr);
return arr;
}
我应该使用AtomicReferenceArray
吗?
非常感谢你的帮助
答案 0 :(得分:3)
在parallelFeed
中,启动送纸器线程。假设您的馈线线程不重叠,并且每个线程都有自己的范围,以便它们一起完全填充阵列。然后在parallelFeed
,join
线程中。 parallelFeed
将等待其他theads完成。假设没有线程无法完成其工作,parallelFeed
"看到"所有索引都已填满。
注意强>
因为你提到" Scala Futures"在你的评论中,看一看 How to wait for several futures有关如何加入"的更多讨论可能发生错误的多个期货。
答案 1 :(得分:1)
如果每个线程只处理它自己的一组索引,那么你需要做的只是{'1}}来自'返回填充数组的线程'的所有线程,以便等到它们全部运行完毕。不,需要join
。
答案 2 :(得分:1)
如果您只想保证可见性,那么您最常使用的是volatile
关键字。不幸的是,volatile
does not work well with arrays,你需要在某种程度上解决它。正如该链接所解释的那样,这是可能的,但我不推荐它。
我会将其作为Future
的集合来实现。每个任务都是Future<String[]>
,“主”线程会将所有结果编译成最终数组。见下文。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Test
{
private String[] arr = new String[2];
public Test() throws Exception // You may want to handle the exceptions more
{ // gracefully than this
final int NUM_THREADS = 10;
ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
// Start the tasks
List<Future<String[]>> tasks = new ArrayList<>();
tasks.add(
executor.submit(() -> partOne())
);
tasks.add(
executor.submit(() -> partTwo())
);
// Compile result
for (Future<String[]> task : tasks)
{
final String[] result = task.get(); // This will wait if necessary
for (int i = 0; i < result.length; ++i)
{
if (result[i] != null) arr[i] = result[i];
}
}
System.out.println(Arrays.toString(arr));
executor.shutdown();
}
private static String[] partOne()
{
String[] arr = new String[2];
arr[0] = "Hello";
return arr;
}
private static String[] partTwo()
{
String[] arr = new String[2];
arr[1] = "World";
return arr;
}
public static void main(String... args) throws Exception
{
new Test();
}
}
答案 3 :(得分:0)
一旦填充数组,您就可以使写入线程写入volatile
字段。然后在volatile
之前阅读return arr
字段。由于volatile
字段的写入/读取确定了happens-before
,因此您将确保数组中数据的可见性。
上面假设必须在线程之间没有额外的同步 - 也就是说,它们不能写入相同的索引,或者像那样写入。
示例代码:
public class WriteReadSyncArray<E> {
private final E[] store;
private volatile boolean sync;
public WriteReadSyncArray(int size) {
this.store = (E[]) new Object[size];
}
public void write(int index, E el) {
store[index] = el;
sync = true;
}
public E[] syncAndReadArray() {
boolean localSync = sync; // establishes happens-before with all previous writes
return store;
}
}