java.单例类懒汉式线程安全问题
2016-04-19 20:21
453 查看
鄙渣渣最近在看多线程,在看线程安全问题的时候,不论是学习视频中强调,还是网上搜的单例类、同步、线程安全的面试题中,都有单例类懒汉式线程安全问题。然后又搜了搜,发现有大牛博客上面写了怎么处理懒汉式线程安全问题,却没有说明理由,所以渣渣我结合自己体会写一下。
先小小的介绍一下,单例类是什么
单例类是一种设计思想
简单的基本思想:私有化结构体,通过判断建立的实例是否为空来判断是否能创建对象。使获取对象的途径不是经过结构体,而是通过定义的get函数。
构建单例类的三个基本:
1.只能有一个实例
2.单例类本身必须要建立这个实例
3.要给其他其他对象提供这一实例
单例类有有两个主流格式,饿汉式和懒汉式,实例代码如下:
饿汉式:
懒汉式:
饿汉式因为在一开始就建立了一个静态对象,所以线程天生安全。
既然饿汉式这么简洁,还线程天生安全,为什么要弄懂懒汉式呢?
因为
面试考的
基本上都是懒汉式
懒汉式为什么线程不安全?
建立多次对象,这是单例类构造中不被允许的。所以存在线程安全问题。
线程安全用同步解决,但如果简单的同步,会使效率变低很多,ex:
就如代码注释中所写,不论时间先后,每一个线程试图进入时,都要对是否持有锁进行判断,效率偏低。
PS。锁就是锁旗标,也有叫“监视器”的,在我看的视频教学中,讲师将其称之为锁,很形象,就这么叫了。具体请见我的另一片文章 java.关于线程同步 。
所以就有了双重判断的格式用来提高效率:
双重判定使第一个进入的线程执行完之后,两个if判断都将返还false,之后尝试进入的线程在if那一关就会停下,不必每个线程都要判断是否持有锁,在一定程度上提高的效率。
最后附加饿汉式线程安全的几个简单的问题
1.懒汉式和饿汉式的区别:懒汉式存在延迟加载
2.懒汉式的延迟加载有没有问题:有,如果多线程访问,会存在线程的安全问题
3.怎么解决:用同步解决,但用一些同步代码块和同步函数都稍微有些低效,用双重判定的形式,能在一定程度上解决低效问题。
4.加同步的时候,用的锁是哪一个:该类所属的字节码文件对象
可能写的不够形象精确。。。。但渣渣已经尽力了。如果有路过的大神发现哪个地方写的不对,还望指正。
以上。
先小小的介绍一下,单例类是什么
单例类是一种设计思想
简单的基本思想:私有化结构体,通过判断建立的实例是否为空来判断是否能创建对象。使获取对象的途径不是经过结构体,而是通过定义的get函数。
构建单例类的三个基本:
1.只能有一个实例
2.单例类本身必须要建立这个实例
3.要给其他其他对象提供这一实例
单例类有有两个主流格式,饿汉式和懒汉式,实例代码如下:
饿汉式:
class Single { private static final Single f = new Single(); private Single(){}; public static Single get() { return f; } } public class Demo { public static void main(String[] args) { Single f =Single.get(); //因为饿汉式在一开始就建立的对象,所以这里只要通过get方法获取引用变量就可以了 } }
懒汉式:
class Singleton { private Singleton(){} //私有化结构体 private static Singleton single; //建立一个变量缓存创建的实例 public static Singleton get() //用来判断是否建立对象 { if (single == null) { single =new Singleton(); } return single; } } public class person { public static void main(String[] args) { Singleton f = Singleton.get(); //获取对象不通过结构体,而是通过get方法 } }
饿汉式因为在一开始就建立了一个静态对象,所以线程天生安全。
既然饿汉式这么简洁,还线程天生安全,为什么要弄懂懒汉式呢?
因为
面试考的
基本上都是懒汉式
懒汉式为什么线程不安全?
class Singleton { private Singleton(){} private static Singleton single; public static Singleton get() { //1.当有例如A、B、C等多个线程同时进入时 if (single == null) { //--》A //--》B //--》C single =new Singleton(); //2.则会建立多次对象 } return single; } } public class person { public static void main(String[] args) { Singleton f = Singleton.get(); } }
建立多次对象,这是单例类构造中不被允许的。所以存在线程安全问题。
线程安全用同步解决,但如果简单的同步,会使效率变低很多,ex:
class Single { private static Single f = null; private Single(){}; public static Single get() { //每一次线程进入,都要对是否持有锁进行判断,效率偏低 synchronized(Single.class) { if(f==null) f = new Single(); } return f; } } public class Demo { public static void main(String[] args) { Single f =Single.get(); } }
就如代码注释中所写,不论时间先后,每一个线程试图进入时,都要对是否持有锁进行判断,效率偏低。
PS。锁就是锁旗标,也有叫“监视器”的,在我看的视频教学中,讲师将其称之为锁,很形象,就这么叫了。具体请见我的另一片文章 java.关于线程同步 。
所以就有了双重判断的格式用来提高效率:
class Single { private static Single f = null; private Single(){}; //4.后续的C线程进入后 public static Single get() { //4.C线程将在这里被拦截,无法进入 //1.如果有A B两个线程同时进入了 if(f==null) //2.--》A // 2.--》B synchronized(Single.class) { //3.只有一个线程能获取锁 //3.--》A if(f==null) //3.当A线程执行完之后,f就不为空了,当之后的B进入的时候,即使B持有锁,也不会进行对象的建立了 f = new Single(); } return f; } } public class Demo { public static void main(String[] args) { Single f =Single.get(); } }
双重判定使第一个进入的线程执行完之后,两个if判断都将返还false,之后尝试进入的线程在if那一关就会停下,不必每个线程都要判断是否持有锁,在一定程度上提高的效率。
最后附加饿汉式线程安全的几个简单的问题
1.懒汉式和饿汉式的区别:懒汉式存在延迟加载
2.懒汉式的延迟加载有没有问题:有,如果多线程访问,会存在线程的安全问题
3.怎么解决:用同步解决,但用一些同步代码块和同步函数都稍微有些低效,用双重判定的形式,能在一定程度上解决低效问题。
4.加同步的时候,用的锁是哪一个:该类所属的字节码文件对象
可能写的不够形象精确。。。。但渣渣已经尽力了。如果有路过的大神发现哪个地方写的不对,还望指正。
以上。
相关文章推荐
- JDK8中matespace的引入
- 【Spring实战】—— 14 传统的JDBC实现的DAO插入和读取
- eclipse window下连接Hadoop2.0报错:local host is: "win/127.0.0.1"; destination host is: "10.2.3.1":50070;
- java多线程问题(下)
- java多线程问题(上)
- java求最大公约数,最小公倍数,斐波那契数列
- Java内存溢出-内存映像分析分析工具-Memory Analyzer
- eclipse快捷键整理
- 胖子实习(一)——SSH(spring3+Struts2+Hibernate4)简单构建框架
- eclipse自动排版快捷键 按了没有用 的解决办法
- Java千百问_05面向对象(007)_java类的继承有什么意义
- Java学习(一)--面向对象(一)
- struts2 Action获取表单内容总结
- 关于Spring Data JPA
- java进制转换
- java利用容器来构建表
- 【非Web工程】Spring + C3P0 + Hibernate + Mysql
- 通过一些实例 学Java
- myeclipse10 下ssh框架搭建检测以及常见问题
- Spring + Spring MVC + MyBatis + Velocity + MySQL 框架搭建