(1)保证一个类只能有一个实例(一个对象)spring
(2)而且提供一个供外界访问该实例的全局访问点数据库
(1)windows的任务管理器、回收站编程
(2)项目中,读取配置文件的类,通常只有一个对象。不必每次使用配置文件的数据都要new一个对象去读取windows
(3)网站的计数器,通常采用单例模式设计,不然没法作到同步设计模式
(4)数据库的链接池设计,通常使用单例模式设计安全
(5)在spring中,每一个bean默认就是单例模式,这样作的优势是spring容器方便管理多线程
(6)在servlet编程中,每一个Servlet也是单例模式并发
(1)减小系统性能的开销:当一个对象的产生须要比较多的资源时,如须要读取配置、产生其余依赖对象时,则能够经过在应用启动时直接产生一个单例对象,而后永久存留在内存中的方式来解决。ide
(2)能够在系统设置全局的访问点。优化共享资源访问,例如能够设计一个单例类,负责全部数据表的映射处理性能
特色:线程安全、调用效率高;可是,不能延时加载
在系统启动的时候,加载该类的时候,因为static的缘由,会当即去加载该类的实例化,同时也因为是static,该类在内存中只有这一个,达到单例的要求。可是,因为是当即加载,会占用系统存储空间,有必定的缺陷。
因为将无参构造器私有化,全部外界想要使用该类,必须经过提供的全局惟一访问点,拿到该类的实例化对象。无论外界获取了多少次对象,在内存中,该类的实例对象只有一个。
public class SingletonDemo02 { private static /*final*/ SingletonDemo02 s = new SingletonDemo02(); private SingletonDemo02(){} // 私有化构造器 public static /*synchronized*/ SingletonDemo02 getInstance(){ return s; } }
特色:线程安全、调用效率不高;可是,能够延时加载
在系统启动的时候,加载该类时,并不会当即去初始化该类;
而是在调用该类的getInstance()方法时,判断当前类是否被建立,若是没有被建立,则进行建立对象,返回。若是已经建立了,直接返回对象。
同时,考虑到并发的状况下,须要使用synchronized,保证每次只有一个线程去访问该类的方法。保证明例化对象的惟一性。
这种方式,属于延迟加载,真正用到该类的时候才会去加载。提升了资源利用率,可是调用getInstance()方法都要同步,并发效率低下。
public class SingletonDemo01 { private static SingletonDemo01 s; private SingletonDemo01(){} // 私有化构造器 public static synchronized SingletonDemo01 getInstance(){ if(s==null){ s = new SingletonDemo01(); } return s; } }
特色:因为JVM底层内部模型缘由,偶尔会出问题,不建议使用
这个模式将同步内容下方到if内部,提升了执行的效率没必要每次获取对象时都进行同步,只有第一次才同步建立了之后就不必了。
public class SingletonDemo03 { private static SingletonDemo03 instance = null; public static SingletonDemo03 getInstance() { if (instance == null) { SingletonDemo03 sc; synchronized (SingletonDemo03.class) { sc = instance; if (sc == null) { synchronized (SingletonDemo03.class) { if(sc == null) { sc = new SingletonDemo03(); } } instance = sc; } } } return instance; } private SingletonDemo03() { } }
特色:线程安全、调用效率高;可是,能够延时加载
将实例化操做放到静态内部类中,外部类没有static,因此,在初始化类的时候,不会当即去加载静态内部类,固然也不会去实例化对象,达到了延迟加载的特性。
只有在调用了getInstance()方法的时候,才会去加载静态内部类。加载类的时候,线程是安全的。
instance是static final修饰的,保证了全局惟一性,即单例性。
兼备并发高效率调用和延迟加载特性。
public class SingletonDemo04 { private static class SingletonClassInstance { private static final SingletonDemo04 instance = new SingletonDemo04(); } public static SingletonDemo04 getInstance() { return SingletonClassInstance.instance; } private SingletonDemo04() { } }
特色:线程安全、调用效率高,不能延时加载
枚举自己就是单例模式。由JVM从根本上提供保障!避免经过反射和反序列化的漏洞!
public enum SingletonDemo05 { /** * 定义一个枚举的元素,它就表明了Singleton 的一个实例。 */ INSTANCE; /** * 单例能够有本身的操做 */ public void singletonOperation(){ // 功能处理 } }
//经过反射的方式直接调用私有构造器 Class<SingletonDemo6> clazz = (Class<SingletonDemo6>) Class.forName("com.bjsxt.singleton.SingletonDemo6"); Constructor<SingletonDemo6> c = clazz.getDeclaredConstructor(null); c.setAccessible(true); SingletonDemo6 s3 = c.newInstance(); SingletonDemo6 s4 = c.newInstance(); System.out.println(s3); System.out.println(s4);
如何避免反射破解单例?
经过在构造方法中手动抛出异常
private SingletonDemo6(){ //私有化构造器 if(instance!=null){ throw new RuntimeException(); } }
//经过反序列化的方式构造多个对象 FileOutputStream fos = new FileOutputStream("d:/a.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s1); oos.close(); fos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt")); SingletonDemo6 s3 = (SingletonDemo6) ois.readObject(); System.out.println(s3);
如何避免反序列化破解单例模式?
表示:在反序列化的时候,若是已经定义了readResolver()方法,则直接返回此方法指定的对象,而不须要单独再建立新对象。
private Object readResolve() throws ObjectStreamException { return instance; }
CountDownLatch类:
同步辅助类,在完成一组正在其余线程中执行的操做以前,它容许一个或者多个线程一直等待。
countDown():当前线程调用此方法,则计数减一,减一放在finally中执行
await():调用此方法会一直阻塞当前线程,直到计数器为0;
public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); int threadNum = 10; final CountDownLatch countDownLatch = new CountDownLatch(threadNum); for(int i=0;i<threadNum;i++){ new Thread(new Runnable() { @Override public void run() { for(int i=0;i<1000000;i++){ // Object o = SingletonDemo4.getInstance(); Object o = SingletonDemo5.INSTANCE; } countDownLatch.countDown(); } }).start(); } countDownLatch.await(); //main线程阻塞,直到计数器变为0,才会继续往下执行! long end = System.currentTimeMillis(); System.out.println("总耗时:"+(end-start)); }
(1)单例对象,占用资源少,不须要延迟加载
枚举式优于饿汉式
(2)单例对象,占用资源大,须要延时加载
静态内部类式优于懒汉式