vlambda博客
学习文章列表

【码农吧干货】单例模式


【码农吧干货】单例模式



/  单例模式  /


官方解释: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 { //线程类用来测试 线程安全性 @Override 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 { //线程类用来测试 线程安全性 @Override public void run() { try { System.out.println(SingleObject.getInstance().hashCode()); } catch (Exception e) {// TODO Auto-generated catch block e.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 { //线程类用来测试 线程安全性 @Override public void run() { try { System.out.println(SingleObject.getInstance().hashCode()); } catch (Exception e) {// TODO Auto-generated catch block e.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 { //线程类用来测试 线程安全性 @Override public void run() { try { System.out.println(SingleObject.getInstance().hashCode()); } catch (Exception e) {// TODO Auto-generated catch block e.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 { //线程类用来测试 线程安全性 @Override public void run() { try { System.out.println(SingleObject.getInstance().hashCode()); } catch (Exception e) {// TODO Auto-generated catch block e.printStackTrace(); } }}


输出:

774856018774856018774856018774856018774856018774856018774856018774856018774856018774856018



/  小结  /


本文介绍单例模式及其两种实现方式——饿汉式和懒汉式,这是单例模式的最常见的两种实现方式,其实单例模式的实现方式不只这两种,还包括静态代码块和枚举方式实现的单例模式,下一篇文章中再讨论。



end












转发是最好的赞赏!!!