关于线程值同步问题

关于多线程中的while(true)这个问题困扰了我很久,在今天终于豁然开朗。下面主要讲解多个线程中共同使用全局静态boolean变量其中一个线程改变其状态,观看其他线程是否跳出while()循环

先上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

/**
* 用来验证多线程值同步问题
*/
public class MyThread {
public static boolean bool=true;
public static void main(String[] args) {
thread_1 a=new thread_1();
a.start();
thread_3 c=new thread_3();
c.start();
thread_2 b=new thread_2();
b.start();
System.out.println((int)'a');
}
}
class thread_1 extends Thread{
@Override
public void run() {
while (MyThread.bool){
}
System.out.println("1end");
}
}
class thread_2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
}
MyThread.bool=false;
}
}

class thread_3 extends Thread{
@Override
public void run() {
System.out.println(74);
while (MyThread.bool){
}
System.out.println("3end");
}
}

以上代码我们开启了三个线程,在线程二中我们改变了bool的值使其变为false 线程一与线程三分别在while(boo);

打住不要往下看我们先想一想执行结果是怎样的呢 是不是1end跟3end都会打印在控制台呢,

揭晓谜底

实际上并没有在控制台打印出13end 这是为什么呢,java内存模型(Java Memory Model 简称JMM)中提到线程之间的共享变量存储在主内存中,每个线程都有一个私有的本地内存,本地内存中存储的是该线程读写主内存共享变量的副本。因为我们未加同步手段所以以上代码将会被编译器优化为以下代码片段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class MyThread {
public static boolean bool=true;
public static void main(String[] args) {
thread_1 a=new thread_1();
a.start();
thread_3 c=new thread_3();
c.start();
thread_2 b=new thread_2();
b.start();
System.out.println((int)'a');
}
}
class thread_1 extends Thread{
@Override
public void run() {
if(MyThread.bool){
while (true){
}
}
System.out.println("1end");
}
}
class thread_2 extends Thread{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
}
MyThread.bool=false;
}
}

class thread_3 extends Thread{
@Override
public void run() {
System.out.println(74);
if(MyThread.bool){
while (true){
}
}
System.out.println("3end");
}
}

发现哪里不一样了吗,之前的while(MyThread.bool)被改变成了if(MyThread.bool){while (true) },这是由于编译优化做的改动,为什么会这样改动呢,因为我们并未对MyThread.bool做任何同步操作,所以在线程1线程3中对于变量MyThread.bool取值就在工作内存中取得,由于该线程未对bool变量这任何状态改变,所以编译器会认为该值的状态就不会被改变了。

理解

引起该问题发送并不是我们未加同步手段导致线程2对共享变量bool值的改变不会被线程1与3发现,这点在JMM中也有提到,只是线程之间的状态统一不是同步发生的,这一点也是线程不安全的由来。

如何解决

这里最简单的解决方法就是把bool设置为public static volatile boolean bool=true; 重点是volatile关键字,该关键字表示线程每次对变量bool的读取都需要同步主内存中的值,所以就会使线程中的while不会被编译器优化。那么改变bool = false;便会使线程1与线程3及时停止。

注意

volatile关键字并不会保证线程安全,该关键字只保证每次读取变量是会同步工作内存与主内存中的值,但是如果存在多个线程同时改变volatile关键字的值就会导致线程不安全。

文章目录
  1. 1. 先上代码
  2. 2. 揭晓谜底
  3. 3. 理解
  4. 4. 如何解决
  5. 5. 注意
,