![](/img/trans.png)
[英]How to use volatile boolean to check whether the thread should run? (Java)
[英]Should volatile variables in Java not be visible on second thread?
我有一個帶有兩個線程A
和B
的小示例應用程序。 兩者都在每個 volatile 變量上設置一個值之前花費一些 CPU 周期( A
設置x
的值, B
設置y
的值),然后B
也打印出這兩個變量。 當這個游戲重復多次時,有時x
的值在B
可見,但有時不可見(即使x
和y
都是易變的)。 這是為什么?
public class Vol2 {
public static volatile int x = 0;
public static volatile int y = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 50; i++) {
x = 0;
y = 0;
Thread t1 = new Thread(() -> {
doWork();
x = 5;
});
Thread t2 = new Thread(() -> {
doWork();
y = 6;
System.out.println("x: " + x + ", y: " + y);
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
public static void doWork() {
int s = 0;
for (int i = 0; i < 1_000_000; i++) {
s += i;
}
}
}
線程t1
和t2
可以同時執行。 有沒有保證, t1
將指派x
之前t2
已分配y
和讀取x
。
像這樣試試。 分配變量,然后做一些工作。 這使每個線程都有機會設置該值。 線程總是花費有限的時間來啟動和異步啟動,因此無法預測開始時的事件。
public class Vol2 {
public static volatile int x = 0;
public static volatile int y = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 50; i++) {
x = 0;
y = 0;
Thread t1 = new Thread(() -> {
x = 5;
doWork();
});
Thread t2 = new Thread(() -> {
y = 6;
doWork();
System.out.println("x: " + x + ", y: " + y);
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
public static void doWork() {
int s = 0;
try {
Thread.sleep(10);
} catch (InterruptedException ie){}
}
}
你的例子有一些微妙的問題。 首先是doWork
可能完全沒用,它沒有任何副作用,而JIT
可以完全消除它。 想一想:既然那個循環純粹是一個沒有人看到的本地事物,那么首先為什么要這樣做?
然后,您對Thread::start
有某種錯誤的理解,這個答案已經向您解釋了。 t1.start();
安排一個線程啟動,並不意味着它會在t2.start();
之前完成(甚至啟動t2.start();
.
然后,至少恕我直言,您使用了錯誤的工具來完成這項工作。 您需要jcstress ,這是專家為此類事情量身定制的工具。 這是您的代碼使用它的樣子:
@JCStressTest
@State
@Outcome(id = "0, 0", expect = Expect.FORBIDDEN, desc = "can not happen")
@Outcome(id = "0, 6", expect = Expect.ACCEPTABLE, desc = "writerY only")
@Outcome(id = "5, 6", expect = Expect.ACCEPTABLE, desc = "both")
public class TwoThreads {
volatile int x = 0;
volatile int y = 0;
@Actor
void writerX(II_Result r) {
x = 5;
}
@Actor
void writerY(II_Result r) {
y = 6;
r.r1 = x;
r.r2 = y;
}
}
如何運行它以及它意味着什么 - 對你來說是一個練習,但主要的一點是運行它只會給你兩種可能的結果:
5, 6 --> meaning writerX finished its work before writerY
或轉換為您的代碼, t1
之前t2
。
0, 6 --> meaning writerY finished its work before writerX
因此, writerX
x = 5
丟失且從未記錄。 或者,轉換為您的代碼, t2
在t1
之前完成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.