1.饿汉式单例
2.懒汉式单例
3.静态内部类单例
4.枚举式单例
5.ThreadLocal线程单例
6.注册式单例
1.饿汉式单例:
特点: 程序启动时即创建好对象
优: 没有线程安全的问题
缺点:在创建的对象数量较多时可能会创建很多的无用对象,浪费资源
package com.cultivator1.singleton.hungry; public class HungrySingletion { private static final HungrySingletion HUNGRY_SINGLETION = new HungrySingletion(); public HungrySingletion() { } public static HungrySingletion getInstance() { return HUNGRY_SINGLETION; } }
public class HungrySingletionTest { public static void main(String[] args) { System.out.println(HungrySingletion.getInstance()); System.out.println(HungrySingletion.getInstance()); } }
2.懒汉式单例 :
特点: 在需要时创建对象
优: 因为在需要时才创建对象,所以消耗更少的资源
缺: 容易出现线程安全的问题(可能通过双重检查锁来避免资源浪费的同时,较少地影响效率)
简单单例
public class LazySingleton { private static LazySingleton lazySingleton; private LazySingleton() { } public static LazySingleton getInstance() { if (lazySingleton == null) { lazySingleton = new LazySingleton(); } return lazySingleton; } }
public class LazySingletonRunnable implements Runnable { @Override public void run() { System.out.println(LazySingleton.getInstance()); } }
public class LazySingletonTest { public static void main(String[] args) { // LazySingleton lazySingleton = LazySingleton.getInstance(); // System.out.println(LazySingleton.getInstance()); // System.out.println(LazySingleton.getInstance()); Thread thread = new Thread(new LazySingletonRunnable()); Thread thread2 = new Thread(new LazySingletonRunnable()); Thread thread3 = new Thread(new LazySingletonRunnable()); thread.start(); thread2.start(); thread3.start(); } }
双重检查锁单例
public class DoubleCheck { private static DoubleCheck doubleCheck; private DoubleCheck() { } public static DoubleCheck getInstance() { if (doubleCheck != null) { return doubleCheck; } synchronized (DoubleCheck.class) { if (doubleCheck != null) { return doubleCheck; } doubleCheck = new DoubleCheck(); return doubleCheck; } } }
public class DoubleCheckRunnable implements Runnable { @Override public void run() { System.out.println(DoubleCheck.getInstance()); } }
public class DoubleCheckTest { public static void main(String[] args) { Thread thread = new Thread(new DoubleCheckRunnable()); Thread thread2 = new Thread(new DoubleCheckRunnable()); Thread thread3 = new Thread(new DoubleCheckRunnable()); thread.start(); thread2.start(); thread3.start(); } }
3.静态内部类单例:
特点: 单例是内部类
优点: 调用内部类时才会创建对象,资源浪费少
缺: 容易被反射破坏(可能通过构造方法判断来避免)
public class InnerSingleton { private InnerSingleton() { if (InnerSingletonSub.INSTANCE != null) { throw new RuntimeException("单例对象不允许重复"); } } public static InnerSingleton getInstance() { return InnerSingletonSub.INSTANCE; } /** * 外部类调用时会调用内部类, 一旦调用 new InnerSingleton(),会先调用这里,再new new * InnerSingleton(),所以反射也会报错 */ private static class InnerSingletonSub { private static final InnerSingleton INSTANCE = new InnerSingleton(); } }
public class InnerSingletonTread implements Runnable { @Override public void run() { System.out.println(InnerSingleton.getInstance()); } }
public class InnerSingletonTest { public static void main(String[] args) { try { Class clazz = InnerSingleton.class; Constructor constructor = clazz.getDeclaredConstructor(null); constructor.setAccessible(true); InnerSingleton innerSingleton = (InnerSingleton)constructor.newInstance(); System.out.println("反射: " + innerSingleton); } catch (Exception e) { e.printStackTrace(); } Thread thread = new Thread(new InnerSingletonTread()); Thread thread2 = new Thread(new InnerSingletonTread()); Thread thread3 = new Thread(new InnerSingletonTread()); thread.start(); thread2.start(); thread3.start(); } }
注册式单例:
特点:对象单例集中管理到一个注册中心
优: 对象集中管理,更加方便
缺: 调用也会相对复杂一些(可能用类的全路径来避免重复),有全程安全的问题(可以通过加锁解决)
public class ContainerSingleton { private static Map<String, Object> ioc = new ConcurrentHashMap<>(); private ContainerSingleton() { } public static Object getInstance(String className) { try { if (!ioc.containsKey(className)) { synchronized (ioc) { if (!ioc.containsKey(className)) { ioc.put(className, Class.forName(className).newInstance()); } } } } catch (Exception e) { e.printStackTrace(); } return ioc.get(className); } }
public class ContainerSingletonThread implements Runnable { @Override public void run() { System.out.println(ContainerSingleton.getInstance("com.cultivator1.singleton.container.ContainerSingletonTest")); } }
public class ContainerSingletonTest { public static void main(String[] args) { Thread thread = new Thread(new ContainerSingletonThread()); Thread thread2 = new Thread(new ContainerSingletonThread()); Thread thread3 = new Thread(new ContainerSingletonThread()); thread.start(); thread2.start(); thread3.start(); // System.out.println(ContainerSingleton.getInstance("com.cultivator1.singleton.container.ContainerSingletonTest")); // System.out.println(ContainerSingleton.getInstance("com.cultivator1.singleton.container.ContainerSingletonTest")); // System.out.println(ContainerSingleton.getInstance("com.cultivator1.singleton.container.ContainerSingletonTest")); } }
4.枚举式单例
特点: 运用枚举的方式创建单例
优点: 没有线程安全的问题
缺点: 在程序启动时即创建单例(本质上是一个饿汉式单例)
public enum EnumSingleton { INSTANCE; public static EnumSingleton getInstance() { return INSTANCE; } }
public class EnumSingletonTest { public static void main(String[] args) { System.out.println(EnumSingleton.getInstance()); System.out.println(EnumSingleton.getInstance()); System.out.println(EnumSingleton.getInstance()); System.out.println(EnumSingleton.getInstance()); try { Constructor constructor = EnumSingleton.class.getDeclaredConstructor(); constructor.setAccessible(true); System.out.println(constructor.newInstance()); } catch (Exception e) { e.printStackTrace(); } } }
5.线程单例 :
特点: 在单个线程中对象只有一个,适用于线程内的变量共享,例如多数据库切换,线程变量共享
public class ThreadLocalSingleton { private static ThreadLocal<ThreadLocalSingleton> threadLocal = new ThreadLocal<>(); private ThreadLocalSingleton() { } public static ThreadLocalSingleton getInstance() { if (threadLocal.get() == null) { threadLocal.set(new ThreadLocalSingleton()); } return threadLocal.get(); } }
public class ThreadLocalSingletonThread implements Runnable { @Override public void run() { System.out.println(ThreadLocalSingleton.getInstance()); } }
public class ThreadLocalSingletonTest { public static void main(String[] args) { System.out.println(ThreadLocalSingleton.getInstance()); System.out.println(ThreadLocalSingleton.getInstance()); System.out.println(ThreadLocalSingleton.getInstance()); System.out.println(ThreadLocalSingleton.getInstance()); Thread thread = new Thread(new ThreadLocalSingletonThread()); Thread thread2 = new Thread(new ThreadLocalSingletonThread()); Thread thread3 = new Thread(new ThreadLocalSingletonThread()); thread.start(); thread2.start(); thread3.start(); } }
6.注册式单例 :
特点: 所有的对象都存在一个容器中
优点: 在需要时创建单例,
缺点: 都在同一个地方获取对象(可以在启动时判断下他们的唯一性,使用时再创建),有线程安全的问题(可以通过双重检查锁来避免,虽然ConcurrentHashMap通过锁分段技术避免了死锁的同时,提升了效率,但是无法避免对象添加时的重复创建对象的问题)
public class ContainerSingleton { private static Map<String, Object> ioc = new ConcurrentHashMap<>(); private ContainerSingleton() { } public static Object getInstance(String className) { try { if (!ioc.containsKey(className)) { synchronized (ioc) { if (!ioc.containsKey(className)) { ioc.put(className, Class.forName(className).newInstance()); } } } } catch (Exception e) { e.printStackTrace(); } return ioc.get(className); } }
public class ContainerSingletonThread implements Runnable { @Override public void run() { System.out.println(ContainerSingleton.getInstance("com.cultivator1.singleton.container.ContainerSingletonTest")); } }
public class ContainerSingletonTest { public static void main(String[] args) { Thread thread = new Thread(new ContainerSingletonThread()); Thread thread2 = new Thread(new ContainerSingletonThread()); Thread thread3 = new Thread(new ContainerSingletonThread()); thread.start(); thread2.start(); thread3.start(); // System.out.println(ContainerSingleton.getInstance("com.cultivator1.singleton.container.ContainerSingletonTest")); // System.out.println(ContainerSingleton.getInstance("com.cultivator1.singleton.container.ContainerSingletonTest")); // System.out.println(ContainerSingleton.getInstance("com.cultivator1.singleton.container.ContainerSingletonTest")); } }