为什么这不正确同步?

时间:2013-05-10 20:42:51

标签: java multithreading synchronization synchronized

大家好我有这段代码:

public class ThreadTester {
    public static void main(String args[]) {
        Counter c = new Counter();
        for (int i = 0; i < 10; i++) {
            MyThread a = new MyThread(c);
            MyThread b = new MyThread(c);
            a.start();
            b.start();
        }   
        System.out.println("The value of the balance is " + c.getVal());
    }
}

class MyThread extends Thread {
    private Counter c;
    public MyThread(Counter c){ this.c = c; }
    public void run(){ s.increment(); }
}

class Counter {
    private int i = 100;
    public synchronized void increment(){ i++; }
    public synchronized int getVal(){ return i; }
}

现在我认为这应该给出120的期望结果 - 但是结果似乎在115和120之间波动。如果我在Thread.sleep(1)之后添加b.start()我总是得到所需的结果120为什么会这样?

这让我很困惑,我很感激能得到的任何帮助,谢谢

5 个答案:

答案 0 :(得分:3)

启动所有线程后打印计数器的值,而不是在所有线程完成之后打印。

在已经开始等待它们完成的所有线程上使用Thread.join(),然后打印该值。或者使用CountDownLatch。睡觉会意外地给你正确的结果。它允许所有线程完成,但仅仅因为他们只有很少的事情要做,睡眠1毫秒就足够了。

答案 1 :(得分:1)

因为线程并行运行。

在一个或多个其他线程增加之前,您正在主线程中打印c.getVal()

当你睡觉时,你允许其他线程有足够的时间来完成,然后打印。

答案 2 :(得分:0)

因为到达System.out时并非所有线程都完成了增量任务。注入睡眠允许线程在到达输出之前完成。

答案 3 :(得分:0)

原因:

第三个线程(执行main())函数在以随机顺序启动线程a和b之后立即进入以下语句,这就是为什么会得到不可预测的结果。

    System.out.println("The value of the balance is " + c.getVal());

下一个问题:

  

如果我在b.start()之后添加一个Thread.sleep(1),我总会得到120的预期结果。为什么会这样?

这是因为您停止主线程足够长(在CPU世界中1秒是很长时间)以允许线程a和b完成。

解决方案:使主线程等待,直到线程a和b都完成。一种方式:

    Counter c = new Counter();
    for (int i = 0; i < 10; i++) {
        MyThread a = new MyThread(c);
        MyThread b = new MyThread(c);
        a.start();
        b.start();
    }   
    a.join(); // wait for thread a to finish
    b.join(); // wait for thread b to finish

    System.out.println("The value of the balance is " + c.getVal());

答案 4 :(得分:0)

您正在线程完成之前打印结果(这就是结果变化的原因)。在打印结果之前,您需要等待所有线程完成

重新构建main方法,如下所示:

public static void main(String args[]) {
    Counter c = new Counter();
    MyThread[] a = MyThread[20];
    for (int i = 0; i < 20; i++) {
        a[i] = new MyThread(c);
        a[i].start();
    }
    for (int i = 0; i < 20; i++) {
        a[i].join();        
    }
    System.out.println("The value of the balance is " + c.getVal());
}

首先,我循环20次,因为你的循环迭代了10次,同时创建了两个线程(所以你也创建了20个线程)。您需要保持引用(通过a数组),以便主线程可以等到所有线程都完成(使用join)。完成所有操作后,将返回正确的结果。