Java同步无法正常工作

时间:2013-03-10 14:29:16

标签: java synchronization

我正在尝试一个小程序来演示同步,但不管出于什么原因,它都没有达到我的期望。关键是要生成1000个线程,并将它们全部加1到静态Integer对象“sum”。输出应该是1000但我得到不同的输出。这就像addSum()方法根本没有同步。我试过延迟println,认为它打印得太快但这不是问题。 我在这里缺少什么?

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);
}

}

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:0)

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

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

此外,在这种情况下,使变量volatile无用且不安全。

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

此外,这里要记住当一个人想要制作变量volatile时的规则:

  

您可以在a下使用volatile变量而不是lock   有限的情况。必须符合以下两个标准   满足volatile变量以提供所需的线程安全性:
  写入变量不依赖于其当前值   该变量不参与其他变量的不变量。

答案 2 :(得分:-2)

您还可以sum AtomicInteger

然后addSum()将如下所示。

public static AtomicInteger sum = new AtomicInteger(0);

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

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

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);
}

}