–
借用Google JEREMY MANSON 的解释,上图表示两个线程并发执行,而且代码顺序上为Thread1->Thread2
1、不用 volatile
假如ready字段不使用volatile,那么Thread 1对ready做出的修改对于Thread2来说未必是可见的,是否可见是不确定的.假如此时thread1 ready泄露了(leak through)了,那么Thread 2可以看见ready为true,但是有可能answer的改变并没有泄露,则thread2有可能会输出 0 (answer=42对thread2并不可见)
注 意
文末有:3625页互联网大厂面试题
2、使用 volatile
[**1、**每次修改volatile变量都会同步到主存中
**2、**每次读取volatile变量的值都强制从主存读取最新的值(强制JVM不可优化volatile变量,如JVM优化后变量读取会使用cpu缓存而不从主存中读取)
**3、**线程 A 中写入 volatile 变量之前可见的变量, 在线程 B 中读取该 volatile 变量以后, 线程 B 对其他在 A 中的可见变量也可见. 换句话说, 写 volatile 类似于退出同步块, 而读取 volatile 类似于进入同步块]( )
所以如果使用了volatile,那么Thread2读取到的值为read=>true,answer=>42,当然使用volatile的同时也会增加性能开销
注意
–
publicclassVolatileTest{
privatestaticvolatileint count = 0;
privatestaticfinalint times = Integer.MAX_VALUE;
publicstaticvoid main(String[] args) {
long curTime = System.nanoTime();
Thread decThread = newDecThread();
decThread.start();
// 使用run()来运行结果为0,原因是单线程执行不会有线程安全问题
// new DecThread().run();
System.out.println("Start thread: “+ Thread.currentThread() + " i++”);
for(int i = 0; i < times; i++) {
count++;
}
System.out.println("End thread: “+ Thread.currentThread() + " i–”);
// 等待decThread结束
while(decThread.isAlive());
long duration = System.nanoTime() - curTime;
System.out.println("Result: "+ count);
System.out.format(“Duration: %.2fs\n”, duration / 1.0e9);
}
privatestaticclassDecThreadextendsThread{
@Override
publicvoid run() {
System.out.println("Start thread: “+ Thread.currentThread() + " i–”);
for(int i = 0; i < times; i++) {
count–;
}
System.out.println("End thread: “+ Thread.currentThread() + " i–”);
}
}
}
最后输出的结果是
原因是i++和++i并非原子操作,我们若查看字节码,会发现
void f1() { i++; }
的字节码如下
void f1();
Code:
0: aload_0
1: dup
2: getfield #2; //Field i:I
5: iconst_1
6: iadd
7: putfield #2; //Field i:I
10: return
可见i++执行了多部操作, 从变量i中读取读取i的值 -> 值+1 -> 将+1后的值写回i中,这样在多线程的时候执行情况就类似如下了
Thread1 Thread2
r1 = i; r3 = i;
r2 = r1 + 1; r4 = r3 + 1;
i = r2; i = r4;
最后
现在正是金三银四的春招高潮,前阵子小编一直在搭建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**
最后
现在正是金三银四的春招高潮,前阵子小编一直在搭建自己的网站,并整理了全套的**【一线互联网大厂Java核心面试题库+解析】:包括Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等**
[外链图片转存中…(img-jq4OYhsh-1720110354043)]