版权声明:本文为博主原创文章,转载请注明出处 浅然的专栏 https://blog.csdn.net/w_linux/article/details/82832544
一、场景简述
笔者在看多线程通信相关问题时,不使用等待/通知机制实现多线程通信的时候,发现b线程没有与a线程发生正常通信。
二、场景实现
如下是未发生正常通信的代码
1、MyList类
package waitnotify;
import java.util.ArrayList;
import java.util.List;
/**
* @author: linjie
* @description: 不使用等待/通知机制实现线程间的通信 list类
* @create: 2018/09/24 18:46
*/
public class MyList {
private List list = new ArrayList();
//向list中添加数据
public void add(){
list.add("xlj");
}
//返回list的大小
public int size(){
return list.size();
}
}
2、线程类A
package waitnotify;
/**
* @author: linjie
* @description: 不使用等待/通知机制的线程类A
* @create: 2018/09/24 18:50
*/
public class ThreadA extends Thread{
private MyList list;
//构造器
public ThreadA(MyList list){
super();
System.out.println("a....");
this.list = list;
}
@Override
public void run(){
try {
for (int i = 0;i < 10;i++){
list.add();
System.out.println("添加了"+(i+1)+"个元素");
Thread.sleep(1000);
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
3、线程类B
package waitnotify;
/**
* @author: linjie
* @description: 不使用等待/通知机制的线程类B
* @create: 2018/09/24 19:12
*/
public class ThreadB extends Thread{
private MyList list;
public ThreadB(MyList list){
super();
System.out.println("b....");
this.list = list;
}
@Override
public void run(){
try{
while (true){
if (list.size() == 5){
System.out.println("==5了,线程b要退出了!");
throw new InterruptedException();
}
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
4、main类
package waitnotify;
/**
* @author: linjie
* @description:不使用等待/通知机制的main类
* @create: 2018/09/24 19:20
*/
public class Test {
public static void main(String[] args){
MyList service = new MyList();
ThreadA a = new ThreadA(service);
a.setName("A");
a.start();
ThreadB b = new ThreadB(service);
b.setName("B");
b.start();
}
}
运行结果如下
可以看到程序处于死循环,并且没有出现 “==5了,线程b要退出了!”
三、场景分析
该现象与Java内存模型有关,Java内存模型如图,可以看出每个线程都有一个自己的本地内存空间,线程执行时,先把变量从主内存读取到线程自己的本地内存空间,然后再对该变量进行操作。然后对该变量操作完后,在某个时间再把该变量刷新回主内存
所以场景代码中,A线程将list读取到本地内存,修改后,再刷新回主内存。
而在JVM 设置成 -server模式运行程序时,线程会一直在私有堆栈中读取list大小,所以B线程一直无法读取到A线程改变的list变量,从而处于死循环,并无法出现 “==5了,线程b要退出了!”
(图片摘取地址在文末)
四、解决方案
在线程类B中对其变量前加volatile,作用即:它强制线程从主内存中取 volatile修饰的变量
volatile private MyList list;