请谈谈你对volatile的理解
volatile是Java虚拟机提供的轻量级同步机制
三大特性:1、保证可见性 2、不保证原子性 3、禁止指令重排
JMM你谈谈
JMM Java内存模型
JMM关于同步的规定:
1、线程解锁前,必须把共享变量的值刷新回主内存。
2、线程加锁前,必须读取主内存的最新值到自己的工作内存。
3、加锁解锁是同一把锁。
import java.util.concurrent.TimeUnit;
class MyData {
volatile int number=0;
public void addTo60() {
this.number=60;
}
}
public class VolatileDemo {
public static void main(String[] args) {
MyData myData = new MyData();
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"\t come in");
try {
TimeUnit.SECONDS.sleep(3);
}catch (InterruptedException e) {
e.printStackTrace();
}
myData.addTo60();
System.out.println(Thread.currentThread().getName()+"\t updated number value: "+myData.number);
},"AAA").start();
while(myData.number==0) {
}
System.out.println(Thread.currentThread().getName()+"\t mission is over: "+myData.number);
}
} volatile不保证原子性案例:
class MyData {
volatile int number=0;
public void addPlusPlus() {
number++;
}
}
public class VolatileDemo {
public static void main(String[] args) {
MyData myData = new MyData();
for (int i=0; i<20; i++) {
new Thread(() -> {
for (int j=0; j<100; j++) {
myData.addPlusPlus();
}
},"BBB").start();
}
while(Thread.activeCount()>2) {
Thread.yield();
}
} System.out.println(Thread.currentThread().getName()+"\t mission is over: "+myData.number);
}
} 结果输出1989,不是2000,所以说程序出现了问题。
那么如何解决原子性呢?
加synchronized?太重了
在包
package java.util.concurrent.atomic中
有Class AtomicInteger
import java.util.concurrent.atomic.*;
class MyData {
AtomicInteger atomicInteger = new AtomicInteger();
public void addAtomic() {
atomicInteger.getAndIncrement();
}
}
public class VolatileDemo {
public static void main(String[] args) {
MyData myData = new MyData();
for (int i=0; i<20; i++) {
new Thread(() -> {
for (int j=0; j<100; j++) {
myData.addAtomic();
}
},"BBB").start();
}
while(Thread.activeCount()>2) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+"\t mission is over: "+myData.atomicInteger);
}
} 为什么AtomicInteger可以解决原子性而不用加synchronized呢?
JMM:
1、可见性 2、原子性 3、有序性
有序性:
计算机在执行程序时,为了提高性能,编译器和处理器常常会对指令重排,一般分为以下3种:
源代码->编译器优化的重排->指令并行的重排->内存系统的重排->最终执行的指令
多线程环境中线程交替执行,由于编译器指令重排的存在,两个线程使用的变量能否保证一致性是无法确定的,结果无法预测。
查看11道真题和解析
