单例模式饿汉和懒汉
单例分为懒汉式和饿汉式:
饿汉式:类加载的时候,创建对象。 因此类加载速度慢, 线程相对安全。
懒汉式:类加载的时候,不会创建对象,调用时才会创建对象。因此类加载速度快,线程相对不安全,一般要配合synchronized使用。
饿汉式:
//饿汉式 public class HungarySingleton { private static HungarySingleton single = new HungarySingleton(); private HungarySingleton() { System.out.println("---new HungarySingleton---"); } public static HungarySingleton getSingle() { return single; } }
懒汉式:
//懒汉式 public class LazySingleton { private static LazySingleton single = null; private LazySingleton() { System.out.println("---new LazySingleton---"); } // 懒汉模式在使用时,容易引起不同步问题,所以应该创建同步锁 // 双重锁写法。在获取对象的时候,先判断是否为空,不为空直接返回,否则就加锁,加完锁然后再次需要判断是否为空。 public static LazySingleton getSingle() { if (single == null) { synchronized (LazySingleton.class) { if (single == null) { single = new LazySingleton(); } } } return single; } }
线程安全性分析:
测试类:
public class Test { public static void main(String[] args) { for (int i = 0; i < 50000; i++) { new Thread() { public void run() { HungarySingleton.getSingle(); } }.start(); } } }


不管是饿汉式还是懒汉式,都只有一个new,说明都是线程安全的。
为什么懒汉式需要用双重锁写法?
我们先注释掉里面的非空判断,再运行测试类。

运行结果:

如果把里面的判null去掉,再去测试。发现有两个输出,说明不是单例。
为什么哪,因为可能出现这种情况,线程A、B同时请求加锁,此时两个线程都已通过了第一个为空的判断,假设A线程先加锁,B线程等待,然后A去创建对象;A释放锁后,B线程加锁,又创建了对象。
单例模式思路:
1.私有属性
2.私有构造方法
3.公开的getSingle方法
单例模式作用:保证了对象的唯一性
适用场景:
1.需要生成唯一序列的环境
2.需要频繁实例化然后销毁的对象。
3.创建对象时耗时过多或者耗资源过多,但又经常用到的对象。
4.方便资源相互通信的环境
最后咱们来谈下,单例模式的优缺点:
优点:
1.实现了对唯一实例访问的可控
2.对于一些需要频繁创建和销毁的对象来说可以提高系统的性能。
缺点:
1.不适用于变化频繁的对象
2.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出。
3.如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失。

浙公网安备 33010602011771号