Java:填充矩阵多线程,目前没有线程安全

时间:2018-02-12 08:39:16

标签: java multithreading thread-safety

我对多线程非常了解,但我认为我或多或少都有了整体想法。我正在尝试填充矩阵多线程,但我的代码显然不是线程安全的,我的矩阵中有重复的列,当矩阵定期填充时不是这种情况。下面是一个示例代码块。请注意,reader是一个Scanner对象,someOperationOnText(someText)返回一个int [100]对象。

    int[][] mat = new int[100][100];
    ExecutorService threadPool = Executors.newFixedThreadPool(8);

    for (int i = 0; i < 100; i++) {
        Set<Integer>someText = new HashSet<>(reader.next());
        int lineIndex = i;
        threadPool.submit(() -> mat[lineIndex] = someOperationOnText(someText);
   }

你认为这不是线程安全的原因吗?我似乎无法理解它,因为读取是在线程池外完成的,我认为它不会有风险。

非常感谢任何调试技巧! GRTS

2 个答案:

答案 0 :(得分:1)

submit调用和执行者线程池中的线程执行lambda之间有一个发生在之前。 (参见javadoc:“记忆一致性效应”)。这意味着lambda将看到someTextmatlineIndex的正确值。

唯一对此不是线程安全的是使用主线程中mat中的值的(隐含)代码。在执行程序上调用shutdown()应该足够了......尽管javadocs没有讨论shutdown()awaitTermination()的内存一致性效果。

(通过阅读ThreadPoolExecutor的{​​{3}},awaitTermination()方法在池线程之间提供发生在之前(在完成所有任务之后)并且该方法的返回。发生 - 之前是由于使用执行程序的主锁来同步池关闭。很难看出它们如何在没有这个(或等效的)的情况下正确实现关闭,所以它不仅仅是一个“实施人工制品”...... IMO。)

答案 1 :(得分:0)

好吧,访问矩阵中的元素是一个非常快速的操作,而计算则不是。

我认为在计算可以并发时同步访问矩阵对你来说是一种正确的方法。

    int[][] mat = new int[100][100];
    Object lock = new Object();
    ExecutorService threadPool = Executors.newFixedThreadPool(8);

    for (int i = 0; i < 100; i++) {
        Set<Integer> someText = new HashSet<>(reader.next());
        int lineIndex = i;
        threadPool.submit(() -> {
            int result = someOperationOnText(someText);
            synchronized (lock) {
                mat[lineIndex] = result;
            }
        });
    }