众所周知,要进行多线程开发必须要先熟悉JAVA并发工具包,工欲善其事必先利其器,下面讨论一下ThreadLocal和volatile的可见性问题!
java.lang.ThreadLocal:
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive;
根据JDK中的解释,ThreadLocal为每个线程维护一份本地变量的副本,只要这个线程是alive,这份副本就一直存在;
volatile是JAVA中的关键字,volatile修饰的变量都会被同步到主存中,根据内存模型理解,同步到主存中也就意味这对其他的线程是可见的;
接下来抛出问题:
如果一个对象Obj是被ThreadLocal维护的,Obj中有一个volatile修饰的成员变量variable,那么variable对于其他线程是可见的吗?
接下来上代码:
对象Obj
/**
* @author wuhuagang
* @date 2019/1/3
* @desc
*/
public class Dto {
private volatile ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
public ByteArrayOutputStream getByteArrayOutputStream() {
return byteArrayOutputStream;
}
public void setByteArrayOutputStream(ByteArrayOutputStream byteArrayOutputStream) {
this.byteArrayOutputStream = byteArrayOutputStream;
}
}
主程维护ThreadLocal
/**
* @author wuhuagang
* @date 2019/1/3
* @desc
*/
public class MainProgram {
public static ThreadLocal<Dto> threadLocal = new ThreadLocal<>();
public static void main(String[] args) throws Exception {
Dto dto = new Dto();
threadLocal.set(dto);
ThreadMain threadMain = new ThreadMain();
threadMain.start();
for(int i = 0;i<100;i++){
dto.getByteArrayOutputStream().write("中国人民很行:".concat(Integer.valueOf(i).toString()).getBytes());
}
}
}
起一个线程去试试成员变量的可见性
/**
* @author wuhuagang
* @date 2019/1/3
* @desc
*/
public class ThreadMain extends Thread{
@Override
public void run() {
Dto dto = MainProgram.threadLocal.get();
while (dto!=null){
System.out.println("content:"+dto.getByteArrayOutputStream().toString());
}
}
}
结果:
content:中国人民很行:0中国人民很行:1中国人民很行:2中国人民很行:3中国人民很行:4中国人民很行:5 。。。
结果说明,volatile修饰的变量,即使变量存储在ThreadLocal的本地副本中,依然会被volatile同步到主存中,对其他线程可见,所以小伙伴们记住,这样的代码,即使是threadlocal结构的也会是产生安全问题的!