使用同步获取意外值

时间:2012-10-28 12:34:07

标签: java multithreading synchronized

我有一个简单的代码片段,并试着用它进行一些实验,但在下一个代码中,我不清楚输出数据的顺序:

public class Main {

    static int n = 100;

    public static synchronized int decreaseValue(){
        return --n;
    }

    public static void main(String[] args) throws InterruptedException, IOException {


        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        System.out.println("Thread1: "+ decreaseValue());
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"Thread1");
        t1.start(); 

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        System.out.println("Thread2: "+ decreaseValue());
                        Thread.sleep(2000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"Thread2");
        t2.start();


        while(true){
            try {
                System.out.println("Main Thread: "+ decreaseValue());
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

无法理解,为什么我会按下一个顺序获得这些值:

线程1:89         线程2:90         主线:88

请注意N值而不是呼叫线的顺序:

Thread1: 99
Thread2: 98
Main Thread: 97
Main Thread: 95
Thread2: 94
Thread1: 96
Main Thread: 92

3 个答案:

答案 0 :(得分:3)

您必须阅读必须使用synchronized以确保正确排序或类似内容的地方。 “排序”一词与你想到的概念有不同的概念:它意味着对同步块的执行总会有一些明确的顺序。订购事先不知道,但每次都会在那里。如果没有同步,你甚至不会得到这样的保证:一个线程可以感知一个订单,另一个线程可以感知不同的订单,或者根本不感知其他线程的任何操作。

关于您的编辑:

如果您担心打印输出无序,这是因为您的println语句不在synchronized范围内,因此可以独立于decreaseValue的调用进行交错。

答案 1 :(得分:2)

线程并行运行。您无法预测其执行顺序。您可以设置优先级执行顺序的线程优先级。

答案 2 :(得分:1)

线程正在并发运行,没有任何东西强加它们应该调用你的decreaseValue()函数。你会期望它们按顺序排列,因为你正在做同样的睡眠:)但是一旦线程从睡眠中启动/恢复,CPU就会将线程放在一个正在运行的队列中(创建执行顺序,这是同步保证的顺序),因此打印顺序取决于CPU如何将线程置于运行队列中。

如果您询问打印指令,控制台上的打印也会同步(但与reduceValue不在同一个程序段中)。相同的逻辑适用于打印,以减少值。

如果您希望以与递减值相同的顺序查看打印件,则可以在decreaseValue()功能中移动打印件。但这不会影响值的递减顺序。