单例模式
设计模式大家都很熟悉,今天来记录下最基础也最简单的单例模式
单例模式分为两类,一是饿汉式,另外就是相对的懒汉式
想来看看饿汉式
常见的实现方式如下:
1 public class SingletonHungry { 2 private static SingletonHungry instance = new SingletonHungry(); 3 4 private String token; 5 6 private SingletonHungry() { 7 token = System.currentTimeMillis() + ""; 8 } 9 10 public static SingletonHungry getInstance() { 11 return instance; 12 } 13 14 public String getToken() { 15 return token; 16 } 17 }
新增token来验证线程安全
来个线程安全的
public class SingletonHungrySafe { private static String token; //jvm加载时会实例化 private static class Holder { private static SingletonHungrySafe INSTANCE = new SingletonHungrySafe(); } private SingletonHungrySafe() { token = System.currentTimeMillis() + ""; } public static final SingletonHungrySafe getInstance() { return Holder.INSTANCE; } public String getToken() { return token; } }
可以保证在各个线程获取Holder.INSTANCE变量之前完成。在保证线程安全的同时,又可以延迟实例化,并且没有降低并发性
接下来看看懒汉式,相对的,懒汉式是用时才加载,延后性。
先来个线程不安全的
public class SingletonLazy { private static SingletonLazy instance; private SingletonLazy() { } public static SingletonLazy getInstance() { if (instance == null) { instance = new SingletonLazy(); } return instance; } }
线程安全的
public class SingletonLazySafe { private volatile static SingletonLazySafe instance; private SingletonLazySafe() { } public static SingletonLazySafe getInstance() { if (null == instance) { synchronized (SingletonLazySafe.class) { if (null == instance) { instance = new SingletonLazySafe(); } } } return instance; } }
双重检查加锁,保证线程安全。
同时,我们可以对这些进行测试
public class SingletonTest { public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 1000; i++) { Single single = new Single(); single.start(); } } static class Single extends Thread { @Override public void run() { checkSingleHungry(); } } private static void checkSingleHungrySafe() { SingletonHungrySafe singletonHungrySafe = SingletonHungrySafe.getInstance(); System.out.println("Thread id=" + Thread.currentThread().getId() + "token:" + singletonHungrySafe.getToken()); } private static void checkSingleHungry() { SingletonHungry singletonHungry = SingletonHungry.getInstance(); System.out.println("Thread id=" + Thread.currentThread().getId() + "token:" + singletonHungry.getToken()); } }
验证线程安全问题