【码农吧干货】单例模式
/ 单例模式 /
官方解释:Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。)
我的理解:单例模式是实现类型最多的设计模式之一,本文给出两种实现模式,饿汉式、懒汉式的单例模式。
参与者:Singleton单例类
类图:
/ 单例模式——饿汉式 /
饿汉式实现步骤
第一步,私有化构造函数;
第二步,定义时初始化;
第三步,定义getInstance()方法返回对象实例;
第四步,新建线程类验证线程安全性(此步骤为验证该种单例实现方式线程安全性,可选)
饿汉式实现代码
/*** Created by 30292 on 2020/6/25.*/public class SingleInstance {public static void main(String[] args) {MyThread _tMyThread = new MyThread();MyThread _tMyThread2 = new MyThread();MyThread _tMyThread3 = new MyThread();_tMyThread.start();_tMyThread2.start();_tMyThread3.start();}}class SingleObject {private SingleObject() { //第一步 私有化构造函数 禁止客户端用new新建对象}//第二步 提供新建对象入口 这里采用饿汉式private static SingleObject _sSingleObject = new SingleObject();//饿汉式 定义时初始化 线程安全// static 方法 保证客户端可以使用类名调用(即保证客户端在未新建对象时 可以调用此方法)public static SingleObject getInstance() {return _sSingleObject;}}class MyThread extends Thread { //线程类用来测试 线程安全性public void run() {System.out.println(SingleObject.getInstance().hashCode());}}
输出:
389269157389269157389269157
/ 单例模式——懒汉式 /
懒汉式实现步骤
第一步,私有化构造函数;
第二步,新建单例引用,并在构造函数中初始化;
第三步,定义getInstance()方法返回对象实例;
第四步,新建线程类验证线程安全性(此步骤为验证该种单例实现方式线程安全性,可选)。
懒汉式——线程不安全
public class SingleInstance {public static void main(String[] args) {for (int i = 0; i < 10; i++) { // 模拟10个线程new MyThread().start();}}}class SingleObject {private SingleObject() { //第一步 私有化构造函数 禁止客户端用new新建对象}private static SingleObject _sSingleObject;// static 方法 保证客户端可以使用类名调用(即保证客户端在未新建对象时 可以调用此方法)public static SingleObject getInstance() throws Exception {Thread.sleep(5000); //通过sleep() 等待5s 让线程不安全的问题暴露出来if (_sSingleObject == null) {_sSingleObject = new SingleObject();}return _sSingleObject;}}class MyThread extends Thread { //线程类用来测试 线程安全性public void run() {try {System.out.println(SingleObject.getInstance().hashCode());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
输出:
1932022484123036851932022481932022481932022483892691571932022481435984462193202248193202248
懒汉式 synchronize同步方法保证线程安全
public class SingleInstance {public static void main(String[] args) {for (int i = 0; i < 10; i++) { // 模拟10个线程new MyThread().start();}}}class SingleObject {private SingleObject() { //第一步 私有化构造函数 禁止客户端用new新建对象}private static SingleObject _sSingleObject;// static 方法 保证客户端可以使用类名调用(即保证客户端在未新建对象时 可以调用此方法)public static synchronized SingleObject getInstance() throws Exception {Thread.sleep(5000); //通过sleep() 等待5s 让线程不安全的问题暴露出来if (_sSingleObject == null) {_sSingleObject = new SingleObject();}return _sSingleObject;}}class MyThread extends Thread { //线程类用来测试 线程安全性public void run() {try {System.out.println(SingleObject.getInstance().hashCode());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
输出:
968687297968687297968687297968687297968687297968687297968687297968687297968687297968687297
懒汉式 synchronized同步代码块保证线程安全
public class SingleInstance {public static void main(String[] args) {for (int i = 0; i < 10; i++) { // 模拟10个线程new MyThread().start();}}}class SingleObject {private SingleObject() { //第一步 私有化构造函数 禁止客户端用new新建对象}private static SingleObject _sSingleObject;// static 方法 保证客户端可以使用类名调用(即保证客户端在未新建对象时 可以调用此方法)public static SingleObject getInstance() throws Exception {Thread.sleep(5000); //通过sleep() 等待5s 让线程不安全的问题暴露出来synchronized (SingleObject.class) { //将需要原子化操作的代码放在同步代码块中,static方法的同步锁为类字节码,非static方法的同步锁为this,此处static方法//同步代码块相对于同步方法 同步的内容少,效率高if (_sSingleObject == null) {_sSingleObject = new SingleObject();}}return _sSingleObject;}}class MyThread extends Thread { //线程类用来测试 线程安全性public void run() {try {System.out.println(SingleObject.getInstance().hashCode());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
输出:
774856018774856018774856018774856018774856018774856018774856018774856018774856018774856018
懒汉式 lock机制保证线程安全
import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class SingleInstance {public static void main(String[] args) {for (int i = 0; i < 10; i++) { // 模拟10个线程new MyThread().start();}}}class SingleObject {private SingleObject() { //第一步 私有化构造函数 禁止客户端用new新建对象}private static Lock lock = new ReentrantLock();private static SingleObject _sSingleObject;// static 方法 保证客户端可以使用类名调用(即保证客户端在未新建对象时 可以调用此方法)public static SingleObject getInstance() throws Exception {Thread.sleep(5000); //通过sleep() 等待5s 让线程不安全的问题暴露出来lock.lock();try {if (_sSingleObject == null) {_sSingleObject = new SingleObject();}} finally {lock.unlock();}return _sSingleObject;}}class MyThread extends Thread { //线程类用来测试 线程安全性public void run() {try {System.out.println(SingleObject.getInstance().hashCode());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
输出:
774856018774856018774856018774856018774856018774856018774856018774856018774856018774856018
/ 小结 /
本文介绍单例模式及其两种实现方式——饿汉式和懒汉式,这是单例模式的最常见的两种实现方式,其实单例模式的实现方式不只这两种,还包括静态代码块和枚举方式实现的单例模式,下一篇文章中再讨论。
end
转发是最好的赞赏!!!
