我目前正在尝试研究并发性,特别是“volatile”关键字。
通过声明计数器变量volatile,对计数器变量的所有写操作都将立即写回主存储器。此外,计数器变量的所有读取都将直接从主存储器中读取。以下是计数器变量的volatile声明如何看起来
和
当线程写入volatile变量时,不仅仅是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)
问题
备注
答案 0 :(得分:3)
volatile关键字提供了一种弱形式的线程安全性。它保证可见性,但不保证原子性或互斥。
易失性字段是否可能不是线程安全的?线程安全。写入非易失性double
和long
值不是原子的,但写入易变的double
和long
变量是。
由所有volatile字段组成的类是否可能不是线程安全的?是的,如果写入字段会导致无效的状态转换(缺少同步)。
(可选)你有没有关于Java Concurrency的好教程 建议?
通常被推荐作为该主题的权威处理的书是Brian Goetz的“Java Concurrency in Practice”。它有点旧了。