Java-我应该使用原子引用阵列吗?

Java-我应该使用原子引用阵列吗?,java,concurrency,parallel-processing,Java,Concurrency,Parallel Processing,我的处境是: 一个新对象用一个大小为n的数组实例化,该数组包含未设置的引用(null) 构建步骤应该为每个索引分配一次引用,然后返回完全填充的数组 其复杂性在于阵列由多个线程并行馈送 我不关心set操作的原子性,因为两个线程不能访问同一个索引,但是,我希望确保返回填充数组的线程“看到”每个填充的索引 private final String[] arr = new String[n]; private void parallelFeed() {...} // Multi-threaded p

我的处境是:

一个新对象用一个大小为
n
的数组实例化,该数组包含未设置的引用(
null

构建步骤应该为每个索引分配一次引用,然后返回完全填充的数组

其复杂性在于阵列由多个线程并行馈送

我不关心set操作的原子性,因为两个线程不能访问同一个索引,但是,我希望确保返回填充数组的线程“看到”每个填充的索引

private final String[] arr = new String[n];

private void parallelFeed() {...} // Multi-threaded

public void build() {
    parallelFeed(arr);
    return arr;
}
我应该使用原子引用阵列吗


非常感谢您的帮助

如果每个线程只处理自己的一组索引,那么您所需要做的就是从“返回填充数组的线程”中加入所有线程,以等待它们全部运行完毕。不需要,需要
AtomicReferenceArray

您可以让写入线程在完成其填充数组的部分后写入
volatile
字段。然后读取
返回arr
之前的
volatile
字段。由于写入/读取
volatile
字段会在
之前建立
,因此可以确保数组中数据的可见性

上面假设线程之间不需要额外的同步——也就是说,它们不能写入相同的索引或类似的smth

示例代码:

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;
    }
}
public类writeredsyncarray{
私人最终电子商店;
私有易失布尔同步;
公共写入Adsyncarray(整数大小){
this.store=(E[])新对象[大小];
}
公共无效写入(整数索引,E el){
存储[索引]=el;
sync=true;
}
公共E[]同步数据库(){
boolean localSync=sync;//建立之前发生的所有写入
退货店;
}
}

如果你只想保证可见性,那么你真正想要的就是关键词。不幸的是,
不稳定
,您需要稍微解决一下。正如那个链接所解释的,这是可能的,但我不推荐这样做

我将把它实现为一个s的集合。每个任务都是一个未来的
,“主”线程将把所有结果编译成最终的数组。见下文

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();
    }
}
import java.util.ArrayList;
导入java.util.array;
导入java.util.List;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.Future;
公开课考试
{
私有字符串[]arr=新字符串[2];
public Test()抛出异常//您可能需要更多地处理异常
{//比这更优雅
最终int NUM_线程数=10;
ExecutorService executor=Executors.newFixedThreadPool(NUM_线程);
//开始任务
列表任务=新建ArrayList();
任务。添加(
执行者提交(()->partOne())
);
任务。添加(
executor.submit(()->partTwo())
);
//编译结果
用于(未来任务:任务)
{
最终字符串[]result=task.get();//如有必要,此操作将等待
对于(int i=0;i
parallelFeed
中,启动进料器线程。假设进料器线程不重叠,并且每个线程都有自己的范围,以便它们一起完全填充阵列。然后在
parallelFeed
join
线程
parallelFeed
将等待其他Thead完成。假设没有线程无法完成其任务,
parallelFeed
“看到”所有索引都已填充

注意

既然你在评论中提到了“Scala Futures”,请看
更多关于如何“连接”可能发生错误的多个期货的讨论。

Volatile.@Michael linked resources没有描述我的建议。那么你的建议是什么?我刚刚意识到OP code暗示的
parallelFeed
应该只在所有编写者完成后返回,例如使用
join
。如果是这种情况,则无需使用
volatile
-join-builds,也可以使用。感谢您的回复,我不确定如何
加入
线程。我目前正在使用Scala未来的API,它与Java的API非常相似。我正在等待futures以
wait.ready(futures.sequence(futures),1.hour)完成
,您知道此操作是否加入线程吗?感谢您的帮助假设
futures
只是一个
Future
s的列表,是的,这应该会起作用(在修复了输入错误后,
futures.sequence
s/b
Future.sequence