即使使用synchronized关键字,线程输出也不一致

时间:2013-02-10 02:25:41

标签: java multithreading synchronization thread-safety

我对线程很新。我编写了一个代码,并期望我的输出始终为20000。但事实并非如此。请找到以下代码:

class Runner4 implements Runnable {

    static int count = 0;

    public synchronized void increase() {
        count++;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            increase();
        }
    }
}

public class threading4 {

    public static void main(String[] args) {

        Thread t1 = new Thread(new Runner4());
        t1.start();
        Thread t2 = new Thread(new Runner4());
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println(Runner4.count);
    }
}

有任何解释吗?

谢谢!

3 个答案:

答案 0 :(得分:1)

您正在同步代码中的两个不同对象(对应于您创建的两个对象)。因此,没有共享静态变量的保护,并且您得到不可预测的结果。基本上,程序中没有有效的同步。您可以通过简单的修改来解决这个问题。

变化:

public synchronized void increase(){
    count++;
}

要:

public void increase(){
    synchronized(Runner4.class) {
        count++;
    }
}

请注意,我并不是说这是完成此类同步的最佳方法 - 但重要的是,如果要修改类级别变量,则还需要类级别同步。

答案 1 :(得分:0)

如果count不是static,您的代码就可以使用。

public synchronized void increase() {
    // method body
} 

相当于

public void increase() {
    synchronized(this) {
        // method body
    }
}

由于countstatict1t2都使用不同的锁访问它,从而导致非确定性行为。要使Runner4.increase在公共锁定上同步(Runner4.classprivate static锁定对象就可以正常工作),或使count非静态。

答案 2 :(得分:0)

你想要达到你想要的方式并不是最好的方法。 更好的方法是定义一个名为Counter的类,如下所示:

public class Counter 
{
    int count;
    public Counter()
    {
        count = 0;
    }
    public synchronized void increase() {
        count++;
    }

    public int getCount()
    {
        return count;
    }

}

该课程有增加计数器和获取计数器的方法。 你现在需要做的是让一个Counter对象由两个调用increase()方法的线程共享。所以你的线程类看起来像这样:

class Runner4 extends Thread {

    Counter count;
    public Runner4(Counter c)
    {
        count = c;
    }


    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            count.increase();
        }

    }
}

请注意,该类接受Counter对象并调用increase方法。该类还扩展了Thread而不是实现Runnable。实际上没有什么区别,刚才你的Runner4可以使用Thread类方法。

从你的主要定义一个Counter对象和两个Runner4线程,然后将Counter对象传递给它们中的每一个:

public static void main(String[] args) {

        Counter count = new Counter();
        Thread t1 = new Runner4(count);
        t1.start();
        Thread t2 = new Runner4(count);
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println(count.getCount());
    }