关于我想知道懒汉模式 为什么要使用volatile关键字这回事

今天发现 项目中有些懒汉模式 貌似有线程安全问题

eg: 大家写懒汉模式是不是都是这样写的呢

public class VolatileTest {  	private static VolatileTest volatileTest =  null;  	public  static VolatileTest of(){     	if(null == volatileTest){         	volatileTest = new VolatileTest();     	}     	return volatileTest; 	} } 

此时会发现如果of再未被调用过,现在多个线程同时调用of方法时,会出现线程安全的问题
(判断是否可能出现多线程的条件:1是否存在多线程。2是否存在共享变量)

怎么解决线程安全问题?
加锁!

eg:现在锁加好了

public class VolatileTest {    private static VolatileTest volatileTest =  null;    public  static VolatileTest of(){       synchronized (VolatileTest.class){           if(null == volatileTest){               volatileTest = new VolatileTest();           }       }       return volatileTest;   } } 

细节1: 这里锁用的VolatileTest.class,锁需要保证在线程中的唯一性。而class是类的模版对象。在jvm加载(生命周期:加载,链接,初始化,使用,卸载)类时 会在内存(堆)中创建唯一一个关于这个类的class对象也就是 VolatileTest.class。

提问:这样写线程是安全了 但是 没有效率。当volatileTest创建好了之后 每次获取都要走锁机制,获取对象都要排队
如何保证 创建时加锁,创建好了就不需要锁了

加判断!
eg: 大家熟知的双检锁来了

public class VolatileTest {      private static VolatileTest volatileTest =  null;      public static VolatileTest of(){         if(null == volatileTest){             synchronized (VolatileTest.class){                 if(null == volatileTest){                     volatileTest = new VolatileTest();                 }             }         }         return volatileTest;     } } 

当volatileTest对象不为null时直接跳过锁返回

好像还有问题!
对象创建大致分三个步骤 1分配内存,2初始化,3返回
指令重排!
也就是说第一个线程创建对象时可能会出现 1.分配内存,3返回,2初始化
这个样依然有很小的概率会出现线程安全问题

加 volatile修饰!

eg:

public class VolatileTest {      private static volatile VolatileTest volatileTest =  null;      public static VolatileTest of(){         if(null == volatileTest){             synchronized (VolatileTest.class){                 if(null == volatileTest){                     volatileTest = new VolatileTest();                 }             }         }         return volatileTest;     } } 

好了,到这里基本解决了懒汉模式线程安全问题

可是我想看字节码上 加volatile和不加volatile的区别

于是。。。
javac 将java文件编程成class文件
javap -v 反编译字节码
结果。。。
加不加 反编译的结果都一样

既然反编译的结果一样 是不是应该去class的16进制文件上找不同?

打开notepad++ 打开class文件 乱码。。。
百度 notepad++ 如何打开16进制文件 安装插件 HEX-Editor
安装失败T。T 我估计是网络问题。

byt 没有工具自己不能造吗!
开动!
利用io流读取class 文件 再将字节流转成16进制打印

eg:读取16进制文件工具类

public class HexRead {     public static void main(String[] args) {         File file = new File("src/test/java/jvm/designmode/VolatileTest.class");         FileInputStream fileInputStream = null;         try {             fileInputStream = new FileInputStream(file);             byte[] bytes = new byte[1024];             int lne = 0;             while ((lne=fileInputStream.read(bytes))!=-1){                 for(int i = 1 ; i < lne+1; i++){                     String s1 = Integer.toHexString(bytes[i-1] & 0xF);                     String s0 = Integer.toHexString((bytes[i-1]>>4) & 0xF);                     System.out.print(s0);                     System.out.print(s1);                     System.out.print(",");                     if((i&0xF) == 0){                         System.out.println();                     }                 } //                System.out.println(Arrays.toString(bytes));             }         } catch (IOException e) {             e.printStackTrace();         }          try {             if(fileInputStream!=null){                 fileInputStream.close();             }         } catch (IOException e) {             e.printStackTrace();         }     } } 

关于我想知道懒汉模式 为什么要使用volatile关键字这回事
看到cafe babe 打印出来简直美滋滋

现在我获得了一个读取16进制文件的工具类

这里就可以看到在字节码的16进制文件中 加volatile和不加volatile的区别 4和0
不禁感叹jvm的强大以及恐怖的节省内存的方式
关于我想知道懒汉模式 为什么要使用volatile关键字这回事

版权声明:玥玥 发表于 2021-06-01 13:30:37。
转载请注明:关于我想知道懒汉模式 为什么要使用volatile关键字这回事 | 女黑客导航