1

我正在尝试制作一个小程序来演示同步,但无论出于何种原因,它都没有达到我的期望。关键是要创建 1000 个线程,并让它们都将 1 加到静态整数对象“sum”上。输出应该是 1000,但我得到不同的输出。这就像 addSum() 方法根本不同步。我试过延迟 println,认为它打印 sum 太快了,但这不是问题。我在这里想念什么?

public class sumsync implements Runnable {
public static Integer sum = new Integer(0);
public sumsync(){
}

private synchronized void addSum(int i){
    sum += i;
}

@Override
public void run() {
    addSum(1);
}
}

主类:

public class sumsyncinit {

private static final int max_threads = 1000;

public static void main(String[] args) {

sumsync task = new sumsync();
Thread thread;

    for(int i=0; i<max_threads;i++){
        thread = new Thread(task);
        thread.start();
    }
    System.out.println(sumsync.sum);
}

}
4

3 回答 3

5

您不是在等待线程完成,因此您无法保证所有增量都已执行。您基本上只是保证addSum方法中一次只有一个线程。您可能想使用Futures来等待结果。

于 2013-03-10T14:33:47.503 回答
0

使用ThreadPoolExecutorhttp://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html)首先有一些池,而不是每次都创建一个新线程,其次, 调用它的awaitTermination方法,以便在打印结果之前等待所有线程终止。

实际上,在您的情况下,您还没有设置一种机制来阻止在所有线程完成其变量增量之后发生打印执行。因此,打印结果可能是随机的。 awaitTermination充当join()所有线程并实现此要求。

此外,在这种情况下,制作变量volatile将是无用且不安全的。

实际上,synchronized关键字已经充当了内存屏障和原子性,而 volatile 仅确保了内存屏障。

此外,当一个人想要创建一个变量时,请记住以下规则volatile

您只能在有限的一组情况下使用 volatile 变量而不是锁。volatile 变量必须满足以下两个条件才能提供所需的线程安全:
对变量的写入不依赖于其当前值。
该变量不参与其他变量的不变量。

于 2013-03-10T14:38:07.950 回答
-2

你也可以制作sum一个AtomicInteger.

然后addSum()会如下图。

public static AtomicInteger sum = new AtomicInteger(0);

private void addSum(int i){
    sum.addAndGet(i);
}

更新:上述解决方案仅用于解决竞争条件。在斯蒂芬在下面发表评论之后,我发布了完整的解决方案,以便主线程在打印最终值之前等待其他线程完成。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class sumsync implements Runnable {
public static AtomicInteger sum = new AtomicInteger(0);
private CountDownLatch latch;
public sumsync(CountDownLatch latch){

  this.latch = latch;
}

private synchronized void addSum(int i){
    sum.addAndGet(i);
}

@Override
public void run() {
    addSum(1);
    latch.countDown();
}
}

import java.util.concurrent.CountDownLatch;

public class sumsyncinit {

private static final int max_threads = 1000;

public static void main(String[] args) {

CountDownLatch latch = new CountDownLatch(max_threads);

sumsync task = new sumsync(latch);
Thread thread;

    for(int i=0; i<max_threads;i++){
        thread = new Thread(task);
        thread.start();
    }
    try {
      latch.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println(sumsync.sum);
}

}
于 2013-03-10T14:39:37.383 回答