我刚开始学习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
返回A
和B
关闭的输出:
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++
),但输出似乎仍然是第一次使用缓存值。
我在这里俯瞰什么?
答案 0 :(得分:6)
你的ThreadSafe
课很好。这很可能是因为线程调度。即,在第一个例子中,线程“A”在从实例获取4278之后但在将其打印到终端之前被取消调度。
然后“B”运行一段时间,取出所有值达7322,并在取消预定之前将所有值打印到7321,此时再次安排“A”,其下一步是打印之前获取的值(4278),继续ThreadSafe
类(7323)中的下一个值。
所以你的问题是,虽然提取数字是正确的线程安全,但打印它们不是。