23 种设计模式 – 单例模式
1. 对于单例模式的一些阐明
单例模式:确保一个类最多只有一个实例,提供一个全局拜访点
留神:
- 单例类只能有一个实例
- 单例类必须本人创立本人的惟一实例
- 单例类必须给所有其余对象提供这一实例
单例模式能够分为两种: 预加载和懒加载 (即饿汉式和懒汉式)
2. 两种模式详解
1. 预加载(饿汉式)
事后加载。还没有应用该单例对象,然而该单例对象就已被加载到内存。
若没有应用该单例对象,该对象就被加载到了内存,会造成内存的节约。
2. 懒加载(懒汉式)
为了防止内存的节约,能够采纳懒加载,即用到该单例对象的时候再创立。
- 单例模式和线程平安
- 饿汉式只有一条语句 return instance, 能够保障线程平安。但会造成内存的节约;
- 懒汉式不节约内存,然而无奈保障线程的平安。首先,if 判断以及其内存执行代码是非原子性的。其次,new Singleton() 无奈保障执行的程序性。不满足原子性或者程序性,线程必定是不平安的,不再赘述;
- 为什么 new Singleton() 无奈保障程序性。创立一个对象分三步:
JVM 为了进步程序执行性能,会对没有依赖关系的代码进行重排序,下面 2 和 3 行代码可能被从新排序。咱们用两个线程来阐明线程是不平安的。线程 A 和线程 B 都创建对象。其中,A2 和 A3 的重排序,将导致线程 B 在 B1 处判断出 instance 不为空,线程 B 接下来将拜访 instance 援用的对象。此时,线程 B 将会拜访到一个还未初始化的对象(线程不平安)。
- 懒汉式的线程平安解决办法
应用 synchronized 关键字。synchronized 加载 getInstace() 函数上的确保障了线程的平安。
Synchronized 是 Java 多线程编程中最罕用的关键字。所有的 Java 对象都有本人惟一的隐式同步锁。该锁只能同时被一个线程取得,其余试图取得该锁的线程都会被阻塞在对象的期待队列中直到取得该锁的线程开释锁能力持续工作。
留神:若要常常的调用 getInstance() 办法,不论有没有初始化实例,都会唤醒和阻塞线程。为了防止线程的上下文切换耗费大量工夫,如果对象曾经实例化了,咱们没有必要再应用 synchronized 加锁,间接返回对象。
把 sychronized 加在 if(instance==null) 判断语句外面,保障 instance 未实例化的时候才加锁。
new 一个对象的代码是无奈保障程序性的,须要应用关键字 volatile 保障对象实例化过程的程序性。
即保障了懒汉式的线程平安。
Java 极客思维
微信扫一扫,关注公众号