knp*_*wrs 2 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++;
}
}
Run Code Online (Sandbox Code Playgroud)
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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
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();
}
}
Run Code Online (Sandbox Code Playgroud)
每当线程关闭时,我得到如下输出:
B: 7320
B: 7321
A: 4278 // What?
A: 7323
A: 7324
Run Code Online (Sandbox Code Playgroud)
返回输出位置A
并B
关闭:
A: 4275
A: 4276
A: 4277
B: 2279 // ROBBLE ROBBLE!
B: 4279
B: 4280
Run Code Online (Sandbox Code Playgroud)
我可以看到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
Run Code Online (Sandbox Code Playgroud)
这次没有跳过任何数字(从中跳过++value
,仍然跳过value++
),但输出似乎仍在使用缓存值.
我在这里俯瞰什么?
你的ThreadSafe
课很好.这很可能是因为线程调度.即,在第一个例子中,线程"A"在从实例获取4278之后但在将其打印到终端之前被解除调度.
那么,"B"跑了一会儿,取所有值高达7322,而被取消调度之前打印高达7321的所有值,此时"A"再次安排,它的下一个步骤是打印有值先前获取(4278),并继续从ThreadSafe
类(7323)的下一个值.
所以你的问题是,虽然获取数字是正确的线程安全,但打印它们不是.