2019.11.2日学习心得

mac2026-08-08  5

单机版单例模式、并发环境的单例模式及其会出现的问题

一.单机版单例模式:

基本代码:

public class Singleton { // 初始化一个单例对象 private static Singleton instance = null; private Singleton() { System.out.println(Thread.currentThread().getName() + "\t 这是构造方法"); } // 提供一个供外部访问本class的静态方法,可以直接调用 public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }

二、并发环境下单例模式:

1.查看在并发模式下时的情况 (1)在类中添加main方法后: public static void main(String[] args) {

//创建10个线程 //结果显示,后台打印的顺序和个数不是一定的 for (int i = 0; i < 10; i++) { new Thread(() -> { Singleton.getInstance(); }, String.valueOf(i)).start(); } }

(2)会出现无法确定的情况: 以上足以说明并发环境下多线程的不确定性

2.问题解决方案:

(1)加synchronized关键字,如下图所示: 弊端分析:结果如图所示可以解决并发条件下的不确定性,但是当该方法在高并发环境下,因为synchronized关键字此时锁住的是整个方法,会随着线程的竞争激烈而使效率成倍降低,所以该方法不可取

(2)DCL(Double Check Lock双端检锁机制) 顾名思义.在加锁前和加锁后都进行一次判断

// 提供一个供外部访问本class的静态方法,可以直接调用 public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; }

但是此时正确率还没有达到百分之百,无法保证线程安全,原因是在多线程环境下为了性能和效果,底层有指令重排的特性,所以不能完全保证运行结果的正确性

(3)问题解决:加入volatile关键字禁止指令重排,保证在对象初始化完成后再去取对象

最新回复(0)