singleton

更新时间:2023-03-02 08:34:45 阅读: 评论:0

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。

饿汉式单例模式

优点

线程安全在类加载的同事已经创建好一个静态对象,调用时反应速度快

缺点

资源效率不高,可能 getInstance() 永远不会执行到执行该类的其他静态方法或者加载了该类 (class.forName),那么这个实例仍然能初始化

public class HungrySingleton { private final static HungrySingleton instance = new HungrySingleton(); private HungrySingleton() { } public static HungrySingleton getInstance() { return instance; } public static void main(String[] args) { /** 线程安全 */ int count = 1000; CountDownLatch countDownLatch = new CountDownLatch(count); for (int i = 0; i < count; i++) { new Thread(() -> { HungrySingleton instance = HungrySingleton.getInstance(); System.out.println(System.currentTimeMillis() + ":" + instance); countDownLatch.countDown(); }).start(); } try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } /** 通过反射 那么这个实例仍然能初始化 */ // try { // Class<?> clazz = Class.forName("hungry.HungrySingleton"); // Object instance1 = clazz.newInstance(); // Object instance2 = clazz.newInstance(); // // System.out.println(instance1); // System.out.println(instance2); // } catch (ClassNotFoundException e) { // e.printStackTrace(); // } catch (IllegalAccessException e) { // e.printStackTrace(); // } catch (InstantiationException e) { // e.printStackTrace(); // } } }

懒汉式单例模式

Lazy_v1_SimpleSingleton

优点

避免了饿汉式的那种在没有用到的情况下创建实例,资源利用率高

缺点

线程不安全执行该类的其他静态方法或者加载了该类 (class.forName),那么这个实例仍然初始化

public class Lazy_v1_SimpleSingleton { private static Lazy_v1_SimpleSingleton instance; private Lazy_v1_SimpleSingleton() { } public static Lazy_v1_SimpleSingleton getInstance() { if (instance == null) { instance = new Lazy_v1_SimpleSingleton(); } return instance; } }

Lazy_v2_SynchronizedSingleton

优点

避免了饿汉式的那种在没有用到的情况下创建实例,资源利用率高线程安全

缺点

第一次加载时不够快,多线程使用不必要的同步开销大执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化

public class Lazy_v2_SynchronizedSingleton { private static Lazy_v2_SynchronizedSingleton instance; private Lazy_v2_SynchronizedSingleton() { } public synchronized static Lazy_v2_SynchronizedSingleton getInstance() { if (instance == null) { instance = new Lazy_v2_SynchronizedSingleton(); } return instance; } public static void main(String[] args) { try { Class<?> clazz = Class.forName("lazy.Lazy_v2_SynchronizedSingleton"); Object instance1 = clazz.newInstance(); Object instance2 = clazz.newInstance(); System.out.println(instance1); System.out.println(instance2); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } }

Lazy_v3_DoubleCheckSingleton

优点

避免了饿汉式的那种在没有用到的情况下创建实例,资源利用率高线程安全

缺点

执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化由于java内存模型一些原因偶尔失败非原子操作给 instance 分配内存调用 instance 的构造函数来初始化成员变量,形成实例将 instance 对象指向分配的内存空间(执行完这步 singleton才是非 null 了) --> 123 or 132结论:如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错;由于有一个『instance已经不为null但是仍没有完成初始化』的中间状态,而这个时候,如果有其他线程刚好运行到第一层 if (instance == null) 这里,这里读取到的 instance 已经不为 null 了,所以就直接把这个中间状态的instance拿去用了,就会产生问题。解决办法Lazy_v4_VolatileDoubleCheckSingleton 不让指令重排序 -lazy.Lazy_v5_InnerClassSingleton 可以指令重排序,但是不让外部看见

public class Lazy_v3_DoubleCheckSingleton { private static Lazy_v3_DoubleCheckSingleton instance; private Lazy_v3_DoubleCheckSingleton() { } public static Lazy_v3_DoubleCheckSingleton getInstance() { if (instance == null) { synchronized (Lazy_v3_DoubleCheckSingleton.class) { if (instance == null) { instance = new Lazy_v3_DoubleCheckSingleton(); } } } return instance; } public static void main(String[] args) { long count = 1000000; synchronizedSingleton(count); noSynchronizedSingleton(count); } private static void synchronizedSingleton(long count) { long start = System.currentTimeMillis(); for (int i = 0; i < count; i++) { Lazy_v3_DoubleCheckSingleton synchronizedSingleton = Lazy_v3_DoubleCheckSingleton.getInstance(); } long end = System.currentTimeMillis(); System.out.println("synchronizedSingleton 耗时:" + (end - start)); } private static void noSynchronizedSingleton(long count) { long start = System.currentTimeMillis(); for (int i = 0; i < count; i++) { HungrySingleton hungrySingleton = HungrySingleton.getInstance(); } long end = System.currentTimeMillis(); System.out.println("noSynchronizedSingleton 耗时:" + (end - start)); } }

Lazy_v4_VolatileDoubleCheckSingleton

优点

避免了饿汉式的那种在没有用到的情况下创建实例,资源利用率高线程安全

缺点

执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化禁止指令重排,导致性能下降

public class Lazy_v4_VolatileDoubleCheckSingleton { /** volatile关键字的一个作用是禁止指令重排,把instance声明为volatile之后,对它的写操作就会有一个内存屏障 */ private static volatile Lazy_v4_VolatileDoubleCheckSingleton instance; private Lazy_v4_VolatileDoubleCheckSingleton() { } public static Lazy_v4_VolatileDoubleCheckSingleton getInstance() { if (instance == null) { synchronized (Lazy_v4_VolatileDoubleCheckSingleton.class) { if (instance == null) { instance = new Lazy_v4_VolatileDoubleCheckSingleton(); } } } return instance; } }

Lazy_v5_InnerClassSingleton

优点

避免了饿汉式的那种在没有用到的情况下创建实例,资源利用率高线程安全

缺点

执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化禁止指令重排,导致性能下降

public class Lazy_v5_InnerClassSingleton { /** * static 是为了使单例的空间共享 * final 保证这个方法不会被重写,重载 */ public static final Lazy_v5_InnerClassSingleton getInstance() { return SingletonHolder.instance; } /** * 这种写法非常巧妙: * 对于内部类 SingletonHolder,它是一个饿汉式的单例实现,在SingletonHolder初始化的时候会 * 由ClassLoader来保证同步,使 instance 是一个真·单例。 * 同时,由于SingletonHolder是一个内部类,只在外部类的Singleton的getInstance()中被使用, * 所以它被加载的时机也就是在getInstance()方法第一次被调用的时候。 * <p> * 从内部看是一个饿汉式的单例,但是从外部看来,又的确是懒汉式的实现。 */ private static class SingletonHolder { private static final Lazy_v5_InnerClassSingleton instance = new Lazy_v5_InnerClassSingleton(); } /** 防止 反射 攻击! */ private static boolean initialized = fal; private Lazy_v5_InnerClassSingleton() { synchronized (Lazy_v5_InnerClassSingleton.class){ if(initialized == fal){ initialized = !initialized; } el{ throw new RuntimeException("单例已被侵犯"); } } } public static void main(String[] args) { try { Class<?> clazz = Lazy_v5_InnerClassSingleton.class; Constructor c = clazz.getDeclaredConstructor(null); c.tAccessible(true); Object o = c.newInstance(); System.out.println(o); Object o1 = c.newInstance(); System.out.println(o1); Object o2 = c.newInstance(); System.out.println(o2); } catch (Exception e) { e.printStackTrace(); } } }

防止序列反序列话单例模式

public class SerializableSingleton implements Serializable { private static final long rialVersionUID = -1994001829338263901L; private SerializableSingleton() { } public final static SerializableSingleton INSTANCE = new SerializableSingleton(); public static SerializableSingleton getInstance(){ return INSTANCE; } /** * @method_name: readResolve * @describe: 防止 序列化和反序列化后 破坏单例模式规则 启用 readResolve() 方法 **/ public Object readResolve() throws ObjectStreamException{ return INSTANCE; } public static void main(String[] args) { SerializableSingleton s1; SerializableSingleton s2 = SerializableSingleton.getInstance(); FileInputStream fis; ObjectInputStream ois; FileOutputStream fos = null; try { fos = new FileOutputStream("rialize.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s2); oos.flush(); oos.clo(); fis = new FileInputStream("rialize.obj"); ois = new ObjectInputStream(fis); s1 = (SerializableSingleton) ois.readObject(); ois.clo(); System.out.println(s1); System.out.println(s2); System.out.println(s1 == s2); } catch (Exception e) { e.printStackTrace(); } } }

注册式单例模式

RegisterSingleton

优点

登记式单例模式可以被挤成(饿汉和懒汉模式构造方法都是稀有的,因而不能被继承的)登记式单例实际上维护的是一组单例类的实例,将这些实例存储到一个Map(登记簿)中,对于已经登记过的单例,则从工厂直接返回,对于没有登记的,则先登记,而后返回

public class RegisterSingletonChildA extends RegisterSingleton { public static RegisterSingletonChildA getInstance() { return (RegisterSingletonChildA) RegisterSingletonChildA .getInstance("org.crayzer.demo.singleton.register.RegisterSingletonChildA"); } //随便写一个测试的方法 public String about() { return "---->我是RegisterSingleton的一个子类RegisterSingletonChildA"; } } public class RegisterSingletonChildB extends RegisterSingleton { public static RegisterSingletonChildB getInstance() { return (RegisterSingletonChildB) RegisterSingletonChildB .getInstance("org.crayzer.demo.singleton.register.RegisterSingletonChildB"); } //随便写一个测试的方法 public String about() { return "---->我是RegisterSingleton的一个子类RegisterSingletonChildB"; } } public class RegisterSingleton { private static Map<String, RegisterSingleton> registerSingletonMap = new ConcurrentHashMap<>(); public static Map<String, RegisterSingleton> getRegisterSingletonMap() { return registerSingletonMap; } protected RegisterSingleton() { System.out.println("RegisterSingleton 的构造函数被调用,创建实例中..."); } public static synchronized RegisterSingleton getInstance(String name) { if (name == null) { name = RegisterSingleton.class.getName(); System.out.println("name不存在,name = " + name); } if (registerSingletonMap.get(name) == null) { try { System.out.println("-->name对应的值不存在,开始创建"); registerSingletonMap.put(name, (RegisterSingleton) Class.forName(name).newInstance()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }el { System.out.println("-->name对应的值存在"); } System.out.println("-->返回name对应的值"); return registerSingletonMap.get(name); } /** * 测试 多线程环境 * @param args */ public static void main(String[] args) { // testMultithreaded(); // System.out.println("=============华丽的分割线============="); testExtends(); } private static void testExtends() { System.out.println("-----------------登记式单例模式----------------"); System.out.println("第一次取得实例(登记式)"); RegisterSingleton s1 = RegisterSingleton.getInstance(null); System.out.println(s1); System.out.println("第二次取得实例(登记式)"); RegisterSingletonChildA s3 = RegisterSingletonChildA.getInstance(); System.out.println(s3); System.out.println(s3.about()); System.out.println("第三次取得实例(登记式)"); RegisterSingletonChildB s4 = RegisterSingletonChildB.getInstance(); System.out.println(s4); System.out.println(s4.about()); System.out.println("第四次取得实例(登记式)"); RegisterSingletonChildB s5 = RegisterSingletonChildB.getInstance(); System.out.println(s5); System.out.println(s5.about()); System.out.println("第五次取得实例(非正常直接new子类的构造方法)"); RegisterSingletonChildB s6 = new RegisterSingletonChildB(); System.out.println(s6); System.out.println(s6.about()); System.out.println("输出父类中Map保存的所有单例,可以看出,直接new出来的实例并没有存在Map中"); System.out.println(s1.getRegisterSingletonMap()); System.out.println(); } public static void testMultithreaded() { int count = 100; CountDownLatch latch = new CountDownLatch(count); for (int i = 0; i < count; i++) { new Thread(() -> { RegisterSingleton singleton = RegisterSingleton.getInstance("org.crayzer.demo.singleton.register.RegisterSingleton"); System.out.println(System.currentTimeMillis() + ":" + singleton); latch.countDown(); }).start(); } try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } RegisterSingleton singleton = new RegisterSingleton(); System.out.println(singleton.getRegisterSingletonMap()); RegisterSingletonChildA singleton1 = new RegisterSingletonChildA(); System.out.println(singleton1.getRegisterSingletonMap()); RegisterSingletonChildB singleton2 = new RegisterSingletonChildB(); System.out.println(singleton2.getRegisterSingletonMap()); } }

Enum

public enum EnumSingleton { RED(){ private int r = 255; private int g = 0; private int b = 0; },BLACK(){ private int r = 0; private int g = 0; private int b = 0; },WHITE(){ private int r = 255; private int g = 255; private int b = 255; }; public void func1() { } public static void main(String[] args) { System.out.println(EnumSingleton.RED); } }

本文发布于:2023-02-28 21:01:00,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/zhishi/a/167771728596763.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:singleton.doc

本文 PDF 下载地址:singleton.pdf

标签:singleton
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 实用文体写作网旗下知识大全大全栏目是一个全百科类宝库! 优秀范文|法律文书|专利查询|