设计模式 单例模式的几种实现方式
一 简介
单例模式,对于一个类只有一个实例化对象。
必要点:
私有化 构造方法,不让new
编写类方法 暴露单例对象
私有化单例对象,只提供给内部使用
二 考虑到并发条件下的情况下
实现方式主要有如下四种
第一种,饿汉模式随着类加载,而实例化。类只会实例化一次,所以不会有并发的问题
/**
* @program: test
* @description: 单例 四种实现方式 第一饿汉式 类加载就初始化
* 第二 懒汉式 方法加锁
* 第三 双重效验
* 第四 静态内部类
* @author:
* @create: 2019-07-09 19:46
*/
public class Singleton {
private Singleton() {
}
private static Singleton singleton = new Singleton();
public static Singleton getSingleton() {
return singleton;
}
}
第二种 对方法封锁,保证临界资源安全,好处:想加载时,才加载
public class Singleton1 {
private static Singleton1 singleton1;
private Singleton1() {
}
public synchronized static Singleton1 getSingleton() {
if(singleton1==null)
singleton1 = new Singleton1(); //只有第一次进入方法体的时候 创建对象
return singleton1;
}
}
对比的是一种,线程不安全的。
/**
* @program: test
* @description: 不加限制的懒加载
* @author:
* @create: 2019-07-09 20:09
*/
public class Singleton4 {
private static Singleton4 singleton4;
private Singleton4() {
}
public static Singleton4 getSingleton() {
if (singleton4 == null) {
singleton4 = new Singleton4();
}
return singleton4;
}
}
第三种 方法:双检验
public class Singleton3 {
private static volatile Singleton3 singleton3;
private Singleton3() {
}
public static Singleton3 getSingleton() {
if (singleton3 == null) {
synchronized (Singleton3.class) {
if (singleton3 == null) {
singleton3 = new Singleton3();
}
} //同样 保证第一次 进入方法体 进行初始化 优化第二种情况
}
return singleton3;
}
}
第四种方法:利用内部类的特性,内部类可以访问外部类的变量;内部类同样也只会加载一次
public class Singleton2 {
private static Singleton2 singleton2;
private Singleton2() {
}
private static class SingletonPv {
private static Singleton2 singleton2 = new Singleton2();
}
private Singleton2 getSingleton() {
return SingletonPv.singleton2;
}
}
最后是测试,让100个线程 同时去获取单例对象,四种方法 都没问题;而没加并发限制,很容易出现100个线程获得的对象不相同的情况
public class Main {
public static void main(String[] args) {
final CountDownLatch countDownLatch = new CountDownLatch(100);
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println( Singleton3.getSingleton()+Thread.currentThread().getName());
}
});
thread.start();
countDownLatch.countDown();
}
}
}