Java同步问题

时间:2011-06-19 00:18:36

标签: java concurrency thread-safety

我刚开始学习Java并发性,我从以下代码中获得了一些奇怪的输出:

ThreadSafe.java:

public class ThreadSafe {
    private int value;

    public ThreadSafe() {
        value = 0;
    }

    public synchronized int getNext() {
        if (value >= 10000) {
            value = 0;
        }
        return value++;
    }
}

RunnableImpl.java:

public class RunnableImpl implements Runnable {
    private String name;
    private ThreadSafe ts;

    public RunnableImpl(String name, ThreadSafe ts) {
        this.name = name;
        this.ts = ts;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(name + ": " + ts.getNext());
        }
    }
}

Main.java:

public class Main {
    public static void main(String[] args) {
        ThreadSafe ts = new ThreadSafe();

        Runnable a = new RunnableImpl("A", ts);
        Runnable b = new RunnableImpl("B", ts);

        new Thread(a).start();
        new Thread(b).start();
    }
}

每当线程关闭时,我得到如下输出:

B: 7320
B: 7321
A: 4278 // What?
A: 7323
A: 7324

返回AB关闭的输出:

A: 4275
A: 4276
A: 4277
B: 2279 // ROBBLE ROBBLE!
B: 4279
B: 4280

我可以看到A早先在4277处停止,在跳过7322并继续使用7323之前在4278处取消。value++++value都会发生这种情况。我的理解是synchronized允许每个线程的方法调用getNext()完成,然后让任何其他线程执行该方法。

当我在private volatile int value;中使用threadsafe.java时,我得到的输出类似于以下内容:

A: 8511
A: 8512
A: 8513
B: 7022 // Meh.
B: 8514
B: 8515

这次没有跳过任何数字(来自++value,仍然会跳过value++),但输出似乎仍然是第一次使用缓存值。

我在这里俯瞰什么?

1 个答案:

答案 0 :(得分:6)

你的ThreadSafe课很好。这很可能是因为线程调度。即,在第一个例子中,线程“A”在从实例获取4278之后但在将其打印到终端之前被取消调度。

然后“B”运行一段时间,取出所有值达7322,并在取消预定之前将所有值打印到7321,此时再次安排“A”,其下一步是打印之前获取的值(4278),继续ThreadSafe类(7323)中的下一个值。

所以你的问题是,虽然提取数字是正确的线程安全,但打印它们不是。