我目前正試圖研究併發性,特別是「volatile」關鍵字。Java - 易失性不按預期工作
通過聲明計數器變量揮發性所有寫計數器變量將被立即寫回主內存。此外,計數器變量的所有讀取都將直接從主存儲器讀取。這裏是計數器變量的volatile聲明的外觀
和
當一個線程寫入volatile變量,那麼不只是volatile變量本身被寫入主存儲器。在寫入volatile變量之前,線程更改的所有其他變量也會刷新到主內存中。當一個線程讀取一個易失變量時,它還會讀取主內存中與易失變量一起刷新到主內存中的所有其他變量。
來源:tutorials.jenkov.com | Java Concurrency - Java Volatile Keyword
這使我得出結論/假設,我做出一個volatile變量的任何變化都會永遠是所有線程可見。所以,我做了一個代碼來測試它。
TestClass
package org.personal.test1;
class TestClass {
public static int w = 0;
public static int x = 0;
public static int y = 0;
public static volatile int z = 0;
private static final int ITERATIONS = 100000;
public static void sooPlus(int indents) {
for (int i = 0; i < TestClass.ITERATIONS; i++) {
TestClass.w++;
TestClass.x++;
TestClass.y++;
TestClass.z++;
}
}
public static void sooMinus(int indents) {
for (int i = 0; i < TestClass.ITERATIONS; i++) {
TestClass.w--;
TestClass.x--;
TestClass.y--;
TestClass.z--;
}
}
public static synchronized String getVariableValues() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("(");
stringBuilder.append("w : "+TestClass.w+", ");
stringBuilder.append("x : "+TestClass.x+", ");
stringBuilder.append("y : "+TestClass.y+", ");
stringBuilder.append("z : "+TestClass.z+")");
return stringBuilder.toString();
}
}
Main Class
package org.personal.test1;
/**
* <ol type="I">
* <li>
* <a href="http://tutorials.jenkov.com/java-concurrency/volatile.html">jenkov.com - Java Volatile Keyword</a>
* </li>
* </ol>
*/
public class Main {
public static void main(String[] args) {
Main.call1();
}
private static void call1() {
Main.test1();
}
private static void test1() {
Thread thread1 = new Thread("Thread1") {
@Override
public void run() {
TestClass.sooPlus(1);
}
};
Thread thread2 = new Thread("Thread2") {
@Override
public void run() {
TestClass.sooMinus(4);
}
};
thread1.start();
thread2.start();
try {
thread1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(TestClass.getVariableValues());
}
}
我得到的結果不是我所期待的。
我得到什麼(變化)
(w : -2314, x : -1692, y : -1416, z : -1656)
我很期待
(w : 0, x : 0, y : 0, z : 0)
或至少
(w : -2314, x : -1692, y : -1416, z : 0)
的問題
- 我是怎麼假設/推斷錯誤,導致不同的輸出少於預期?
- 我的測試方法不正確?如果是,那我該如何解決?
- (可選)有什麼好的Java併發性教程,你推薦?
注意
- 我沒有嘗試讀取類似的問題,但我沒能完全理解提問者試圖以瞭解他的問題做。
volatile關鍵字提供了一種弱的線程安全形式。它保證可見性,但不是原子性或互斥。是否可能會使易變的字段不是線程安全的?是的,如果寫入字段不是原子的。由所有易失性字段組成的類是否可能不是線程安全的?是的,如果寫入字段導致無效狀態轉換(由於缺乏同步)。 – scottb