标签:ati 原因分析 编译 同步 是什么 需要 nts 依赖关系 检测
JMM本身是一种抽象的概念并不真实存在,它描述的是一组规则或规范,通过这组规范顶一了程序各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式。
JMM关于同步的规定:
JMM特性:
示例代码:
class MyData {
//volatile可以保证可见性,及时通知其他线程,主物理内存的值已经被修改
volatile int number = 0;
public void changeNumber() {
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.changeNumber();
System.out.println(Thread.currentThread().getName() + "\t number has change:" + myData.number);
}, "AAA").start();
while (myData.number == 0) {
//TODO
}
System.out.println(Thread.currentThread().getName() + "\t finished");
}
}
示例代码:
class MyData {
volatile int number = 0;
public void addadd() {
number++;
}
}
public class VolatileDemo {
public static void main(String[] args) {
int threadNumber = 20;
MyData myData = new MyData();
CountDownLatch downLatch = new CountDownLatch(threadNumber);
for (int i = 1; i <= threadNumber; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
myData.addadd();
}
downLatch.countDown();
}).start();
}
/*while (Thread.activeCount() > 2) {
}*/
try {
downLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t number:" + myData.number);
}
}
运行结果(运行结果number很小概率会出现20000):
main number:19143
Process finished with exit code 0
出现此结果的原因分析:number++操作被拆分成了3个指令:
public class SingletonDemo {
private static SingletonDemo singletonDemo;
private SingletonDemo() {
System.out.println(Thread.currentThread().getName() + "\t 构造函数");
}
public static SingletonDemo getInstance() {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
return singletonDemo;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
SingletonDemo.getInstance();
}, String.valueOf(i)).start();
}
}
}
运行结果:
1 构造函数
4 构造函数
3 构造函数
2 构造函数
0 构造函数
解决方法:synchronized方法属于重量级锁,并发性不高,不推荐使用。
public static synchronized SingletonDemo getInstance() {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
return singletonDemo;
}
public class SingletonDemo {
private static SingletonDemo singletonDemo;
private SingletonDemo() {
System.out.println(Thread.currentThread().getName() + "\t 构造函数");
}
/**
* DCL(Double Check Lock 双端检查机制)
*
* @return
*/
public static SingletonDemo getInstance() {
if (singletonDemo == null) {
synchronized (SingletonDemo.class) {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
}
}
return singletonDemo;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
SingletonDemo.getInstance();
}, String.valueOf(i)).start();
}
}
}
运行结果:
0 构造函数
从运行结果上看没有问题,但是实际上存在问题:
DCL(双端检锁)机制不一定是线程安全的,原因是有指令重排序的存在,加入volatile可以禁止指令重排。
原因在于某一个线程执行到第一次检测,读取到的singletonDemo的引用对象没有完成初始化。
singletonDemo=new SingletonDemo();可以分为以下3步完成(伪代码)
memory=allocate();///1.分配对象内存空间
instance(memory);///2.初始化对象
instance=memory;///3.设置singletonDemo指向刚分配的内存地址,此时singletonDemo!=null
步骤2和步骤3不存在数据依赖关系,而且无论重排前还是重排后程序的执行结果在单线程中没有改变,因此这种重排优化是允许的。
memory=allocate();///1.分配对象内存空间
instance=memory;///3.设置singletonDemo指向刚分配的内存地址,此时singletonDemo!=null,但是对象还没有初始化完成。
instance(memory);///2.初始化对象
但是指令重排只会保证串行语义的执行一致性(单线程),但并不会关心多线程的语义一致性。
所以当一条线程访问singletonDemo不为null时,由于singletonDemo实例未必初始化完成,也就造成了线程安全问题。
此时添加volatile关键字,可以禁止指令重新排序。
public class SingletonDemo {
private static volatile SingletonDemo singletonDemo;
private SingletonDemo() {
System.out.println(Thread.currentThread().getName() + "\t 构造函数");
}
/**
* DCL(Double Check Lock 双端检查机制)
*
* @return
*/
public static SingletonDemo getInstance() {
if (singletonDemo == null) {
synchronized (SingletonDemo.class) {
if (singletonDemo == null) {
singletonDemo = new SingletonDemo();
}
}
}
return singletonDemo;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(() -> {
SingletonDemo.getInstance();
}, String.valueOf(i)).start();
}
}
}
标签:ati 原因分析 编译 同步 是什么 需要 nts 依赖关系 检测
原文地址:https://www.cnblogs.com/everyingo/p/14553980.html