为什么关于线程的代码显示 a = 1 和 b = 3?为什么添加 "volatile" 不起作用?
why the code about thread shows a = 1 and b = 3? and why add a "volatile" didn't work?
代码如下:
public class ThreadCacheSample {
int a = 1;
int b = 2;
public void change() {
a = 3;
b = a;
}
public void print() {
if (a == 1 && b == 3) {
// why this is happening?
System.out.println("Thread[" + Thread.currentThread().getName() + "]Confused1 : a = 1, b = 3");
} else if (a == 3 && b == 2) {
// why this is happening, too?
System.out.println("Thread[" + Thread.currentThread().getName() + "]Confused2 : a = 3, b = 2");
} else {
System.out.println("Thread[" + Thread.currentThread().getName() + "] b=" + b + ";a=" + a);
}
}
public static void main(String[] args) {
// create many many threads
while (true) {
// create test every time, to make sure a is 1 and b is 2 again
final ThreadCacheSample test = new ThreadCacheSample();
// one thread for changing
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.change();
}
}).start();
// one thread for printing
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.print();
}
}).start();
}
}
}
结果应该是 a = 1,b = 2,或者 a = 3,b = 3。
我的问题是:
为什么我会得到一些显示 "a = 1, b = 3" 或 "a = 3, b = 2" 的结果?
如果我将 "volatile" 添加到 a 和 b,为什么它不起作用?
我认为 volatile 会让每个线程只访问主内存,而不是他们自己的工作内存。所以 volatile 应该是一个解决方案。但是现实告诉我"volatile"也不是办法
public class ThreadCacheSample {
volatile int a = 1;
volatile int b = 2;
...
}
p.s。这是不是关于如何修复代码的问题。就是为什么会出现奇怪的结果?
添加 volatile 会单独增加 a
和 b
修改的可见性(并在其修改的可见性之间添加排序依赖性)。它不是,但是,将任何类型的"atomicity"添加到它们的组合修改中。 "volatile"与否,a
的修改和b
的修改(以及a
的读取和b
的读取)仍然是独立行动!
您的两个 "confused" 答案都是可能的:
案例 1:
- 初始化,a == 1,b == 2
- 打印线程测试"a == 1"
- 更改线程集"a = 3"
- 更改线程集 "a = b" (3)
- 打印线程测试"b == 3"
- 困惑1
案例二:
- 初始化,a == 1,b == 2
- 更改线程集"a = 3"
- 打印线程测试"a == 3"
- 打印线程测试"b == 2"
- 困惑2
请注意,没有 volatile,您可能会得到更古怪的答案,例如看到 "a == 1, b == 3"!
的打印线程
代码如下:
public class ThreadCacheSample {
int a = 1;
int b = 2;
public void change() {
a = 3;
b = a;
}
public void print() {
if (a == 1 && b == 3) {
// why this is happening?
System.out.println("Thread[" + Thread.currentThread().getName() + "]Confused1 : a = 1, b = 3");
} else if (a == 3 && b == 2) {
// why this is happening, too?
System.out.println("Thread[" + Thread.currentThread().getName() + "]Confused2 : a = 3, b = 2");
} else {
System.out.println("Thread[" + Thread.currentThread().getName() + "] b=" + b + ";a=" + a);
}
}
public static void main(String[] args) {
// create many many threads
while (true) {
// create test every time, to make sure a is 1 and b is 2 again
final ThreadCacheSample test = new ThreadCacheSample();
// one thread for changing
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.change();
}
}).start();
// one thread for printing
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
test.print();
}
}).start();
}
}
}
结果应该是 a = 1,b = 2,或者 a = 3,b = 3。
我的问题是:
为什么我会得到一些显示 "a = 1, b = 3" 或 "a = 3, b = 2" 的结果?
如果我将 "volatile" 添加到 a 和 b,为什么它不起作用? 我认为 volatile 会让每个线程只访问主内存,而不是他们自己的工作内存。所以 volatile 应该是一个解决方案。但是现实告诉我"volatile"也不是办法
public class ThreadCacheSample { volatile int a = 1; volatile int b = 2; ... }
p.s。这是不是关于如何修复代码的问题。就是为什么会出现奇怪的结果?
添加 volatile 会单独增加 a
和 b
修改的可见性(并在其修改的可见性之间添加排序依赖性)。它不是,但是,将任何类型的"atomicity"添加到它们的组合修改中。 "volatile"与否,a
的修改和b
的修改(以及a
的读取和b
的读取)仍然是独立行动!
您的两个 "confused" 答案都是可能的:
案例 1:
- 初始化,a == 1,b == 2
- 打印线程测试"a == 1"
- 更改线程集"a = 3"
- 更改线程集 "a = b" (3)
- 打印线程测试"b == 3"
- 困惑1
案例二:
- 初始化,a == 1,b == 2
- 更改线程集"a = 3"
- 打印线程测试"a == 3"
- 打印线程测试"b == 2"
- 困惑2
请注意,没有 volatile,您可能会得到更古怪的答案,例如看到 "a == 1, b == 3"!
的打印线程