单例模式:(确保一个类最多只有一个实例,并提供一个全局访问点)
存在的意义:
有些对象我们只需要一个,如:线程池、缓存、硬件设备等;如果使用多个实例就会造成冲突、不一致等;
比如打印机这个类,如果多个对象同时使用它的输出,打印机类就产生了多个实例,就可能造成打印顺序和内容的混乱;
线程最安全,效率最高的一种写法:
1 public class Singleton { 2 private Singleton(){} 3 private static volatile Singleton instance; 4 //volatile是给编译器用的 5 //定义静态私有变量,不初始化,不使用fina; 6 //使用volatile保证了多线程访问instance变量的可见性, 7 //避免了instance初始化时其它变量属性还没完成赋值是被另外的线程调用 8 public static Singleton getInstance(){ 9 if (instance == null) { 10 synchronized(Singleton.class){ 11 //双重锁保证了创建对象不会被重复执行, 12 //synchronized代码块也很少重复执行, 13 //相比在getInstance方法前添加synchronized更加节约资源 14 if (instance == null) { 15 instance = new Singleton(); 16 } 17 } 18 } 19 return instance; 20 21 } 22 }
事实上,java通过反射机制实例化private类型的构造方法时,此时会使基本上所有的java单例实现失效;
获取单例对象需要保证线程安全,其中方法也要保证线程安全:
说明:资源驱动类,工具类,单例工厂类都需要注意。
应用场景:
1、资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如日志文件,应用配置等。
2、控制资源的情况下,方便资源之间的互相通信。如线程池等。