单例的四个原则
⚫ 构造私有
⚫ 以静态方法或者枚举返回实例
⚫ 确保实例只有一个,尤其是多线程环境
⚫ 确保反序列换时不会重新构建对象
一,懒汉式
当调用创建实例方法的时候创建唯一的实例
1.1 第一种编码-存在线程安全问题
public class LazySingleton01 {
// 构造器私有化
private LazySingleton01(){}
private static LazySingleton01 lazySingleton01=null;
public static LazySingleton01 getInstance(){
if(lazySingleton01==null){
lazySingleton01= new LazySingleton01();
}
return lazySingleton01;
}
1.1.1 单线程运行测试-没问题
public static void main(String[] args) {
for (int i = 0; i <10 ; i++) {
LazySingleton01 instance = LazySingleton01.getInstance();
System.out.println(instance);
}
}
1.1.2 多线程运行测试
// 创建线程
public class SingletonMuchThread implements Runnable{
Set<LazySingleton01> singletons=new HashSet<LazySingleton01>();
public void run() {
LazySingleton01 instance = LazySingleton01.getInstance();
singletons.add(instance);
}
}
// 启动线程
public class TestSingleton {
public static void main(String[] args) throws InterruptedException {
SingletonMuchThread singletonMuchThread=new SingletonMuchThread();
new Thread(singletonMuchThread).start();
new Thread(singletonMuchThread).start();
new Thread(singletonMuchThread).start();
new Thread(singletonMuchThread).start();
new Thread(singletonMuchThread).start();
new Thread(singletonMuchThread).start();
new Thread(singletonMuchThread).start();
Thread.sleep(2000);
System.out.println(singletonMuchThread.singletons);
}
}
1.1.3 结果-未达到单例的效果
1.2 懒汉式线程安全性改进-方式1-加同步锁
public class LazySingleton01 {
// 构造器私有化
private LazySingleton01(){}
private static LazySingleton01 lazySingleton01=null;
public static LazySingleton01 getInstance(){
synchronized (LazySingleton01.class){
if(lazySingleton01==null){
lazySingleton01= new LazySingleton01();
}
}
return lazySingleton01;
}
}
1.3 懒汉式线程安全性改进-方法二 - 双重检查锁
public class LazySingleton01 {
// 构造器私有化
private LazySingleton01(){}
private volatile static LazySingleton01 lazySingleton01=null;
public static LazySingleton01 getInstance(){
if(lazySingleton01==null){
synchronized (LazySingleton01.class){
if(lazySingleton01==null){
lazySingleton01= new LazySingleton01();
}
}
}
return lazySingleton01;
}
}
1.4 静态内部类方式(快速安全)
虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,
如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,
其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕。
如果在一个类的<clinit>()方法中有耗时很长的操作,
就可能造成多个进程阻塞(需要注意的是,其他线程虽然会被阻塞,
但如果执行<clinit>()方法后,其他线程唤醒之后不会再次进入<clinit>()方法。
同一个加载器下,一个类型只会初始化一次。),在实际应用中,这种阻塞往往是很隐蔽的。
————————————————
版权声明:本文为CSDN博主「走着不语」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/mnb65482/article/details/80458571
public class LazySingleton02 {
private LazySingleton02(){}
private static class InnerObject{
private static LazySingleton02 singleton02=new LazySingleton02();
}
public static LazySingleton02 getinstance(){
return InnerObject.singleton02;
}
}
二,饿汉式
把实例在内存中创建好,随时获取唯一一个实例,线程绝对安全
public class HurrySingleton {
private HurrySingleton(){};
private static HurrySingleton singleton=new HurrySingleton();
public static HurrySingleton getInstance(){
return singleton;
}
}