Java多线程不安全,使用synchronized无效

4
一个带有同步的简单多线程测试。我以为如果它被“同步”,其他线程会等待。我错了吗?
public class MultithreadingCounter implements Runnable {

    static int count = 0;

    public static void main(String[] args) {
        int numThreads = 4;
        Thread[] threads = new Thread[numThreads];

        for (int i = 0; i < numThreads; i++)
            threads[i] = new Thread(new MultithreadingCounter(), i + "");

        for (int i = 0; i < numThreads; i++)
            threads[i].start();

        for (int i = 0; i < numThreads; i++)
            try {
                threads[i].join();
            } catch (Exception e) {
                e.printStackTrace();
            }
    }           

    @Override
    public void run() {
        increment();
    }

    public synchronized void increment(){
            System.out.print(Thread.currentThread().getName() + ": " + count + "\t");
            count++; // if I put this first or increment it directly in the print line, it works fine.
    }
}

我认为这应该显示类似以下内容的东西:
0: 1    2: 0    1: 2    3: 3    

但实际输出为:
0: 0    2: 0    1: 0    3: 3    

以及其他类似的变化。它应该按照每个增量(即0,1,2,3)显示,但不是按顺序...

3个回答

8
你的synchronized关键字用在实例方法上。任何两个线程不能同时执行同一个线程对象中的这个方法。但是,你的代码并没有做到这一点。每个线程在自己的实例上执行该方法。同步不会达到你想要的效果。如果该方法是static的,则可以达到预期的效果。

将变量声明为static(与synchronized结合使用)是否足够保证它的线程安全,还是应该将变量声明为volatile - Clockwork-Muse
1
(正确的)同步已经足够了。它已经确保增量与后续读取之间具有happens-before关系,这就是volatile所添加的全部内容。 - Sean Owen

1
你的 increment 方法应该是 静态的:
public static synchronized void increment() {

目前,每个对象都在其各自的实例上同步,但由于count是静态变量,因此您应该在Class对象本身上进行同步。


1
我是让你获得3000声望的人,耶 :D - tckmn

0
当在方法前使用synchronized关键字时,它确保该方法只能被一个线程在同一时间内执行,并且仅针对该对象。它并不能保证来自其他对象的线程安全性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接