【问题标题】:Java n threads updates valueJava n 线程更新值
【发布时间】:2019-05-08 11:11:29
【问题描述】:

我正在尝试同时运行 n 个线程。每个线程应该对不同的数组求和并更新全局值。

很遗憾,全局值更新不正确。

我不想使用 thread.join()。

这是我目前的代码:

public class myClass {
private static class Values {
    private static double sum;

    public synchronized static void add(double dd) {
        sum += dd;
    };
    public synchronized double get() {
        return sum;
    }
}


public static double CreateThreads(double[] array) {
    final Values values = new Values();

    ...
    ...
    ...


    Thread[] threads = new Thread[nOP];

    for (int i = 0; i<threads.length; i++) {


        threads[i] = new Thread(new Runnable() {

            public void run() {

                    Values.add(sum(tab));

            }

        });
        threads[i].start();

    }

    return values.get();
}

public static void main(String[] args) throws IOException {
    double[] arr = createArray(4);
    double sumLogg = CreateThreads(arr);

    System.out.println("\n\nSum: " + sumLogg);      
}

有什么想法吗?

【问题讨论】:

  • 嗯,我刚刚注意到你不想使用.join(),这是为什么呢?
  • 除了你得到的答案:你没有在同一个锁上同步读取和写入:一个在 Values.class 上同步,一个在 Values 中创建的实例上同步CreateThreads 方法(违反命名约定,顺便说一句)。如果您不了解静态字段和实例字段之间的区别,则应该在使用线程之前了解这一点。
  • Values.get 也应该是静态的。但是您正在创建 Values 类的实例。 @ruan 要么全部静态化,要么全部使用单个实例。
  • 您不想使用join,那么您必须使用其他方式等待线程完成(例如CountDownLatchSemaphoreForkJoinTask,... ) .你现在做的方式可能是在任何线程有机会运行之前读取结果。为什么sumadd() 是静态的?

标签: java multithreading java-threads


【解决方案1】:

如果你不想使用 Thread.join,你可以使用 CountDountLatch:

    CountDownLatch cdl = new CountDownLatch(nOP);
    Thread[] threads = new Thread[nOP];
    for (int i = 0; i<threads.length; i++) {
        threads[i] = new Thread(new Runnable() {
            public void run() {
                values.add(sum(tab));
                cdl.countDown();
            }
        });
        threads[i].start();
    }
    cdl.await();

在这种情况下,您不需要使用额外的同步,CountDownLatch 是一个 synchronzier(参见 java.util.concurrent 包描述),根据它的 javadoc“直到计数达到零,动作在一个调用 countDown() 之前的线程,在从另一个线程中的对应 await() 成功返回之后发生的操作之前发生。"

【讨论】:

    【解决方案2】:

    在您的代码中,您使用threads[i].start(); 启动线程,但您永远不会等待它们通过.join() 调用完成执行。这可能会导致您的方法在所有线程完成执行之前返回一个值,从而导致它返回一个不正确的值。

    要解决此问题,请在返回值之前添加如下内容:

    for(Thread t : threads) {
        t.join();
    }
    

    【讨论】:

    • 我不想使用 join()
    • 想知道为什么 OP 说他不想使用 join。这是等待线程结束的好方法。
    • @Teddy 它是使用 join() 的最有效解决方案
    • 是的,如果你想保持“打印答案”直到所有线程都完成求和,那么是的,加入工作。不知道有没有其他好办法。也许你可以在while循环中等待,直到完成操作的线程数等于总线程数。
    • 检查一下 ExecutorService.shutdownNow 的工作原理可能会很有趣。也许他们使用倒计时闩锁?
    猜你喜欢
    • 2013-07-12
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-14
    相关资源
    最近更新 更多