【设计模式】Java多线程保证单例

4 篇文章 0 订阅
2 篇文章 0 订阅
本文探讨了在Java多线程环境中如何确保单例模式的有效性,对比了饿汉模式和懒汉模式,重点分析了懒汉模式的多种解决方案,包括synchronized关键字、静态内置类、序列化与反序列化、静态代码块以及enum实现,并讨论了各自的优缺点和潜在问题。
摘要由CSDN通过智能技术生成

我们常使用单例模式来解决多线程或并发场景下变量数据的安全问题,避免脏数据的产生。
本文主要简单总结下Java多线程中使用单例模式思想的各种实现,并比较这些单例具体实现的优点和缺陷。

文章内容摘自:《Java多线程编程核心技术》 高洪岩 著

单例模式分析

立即加载(饿汉模式)

立即加载:需要使用类的时候,我们已经将对象创建完毕。

饿汉模式,指我们在调用方法前,实例已经被创建了,示例代码如下:

package test;
public class MyObject{
  private static MyObject myObject = new MyObject();
  
  private MyObject(){
  }
  
  public static MyObject getInstance(){
    return myObject;
  }
} 

创建线程类MyThread.java代码如下:

import test.MyObject;

public class MyThread extends Thread{
	@Override
	public void run(){
		System.out.println(MyObject.getInstance().hashCode());
	}
}

创建一个运行主类Run.java:

import extthread.MyThread;
public class Run{
	public static void main(String[] args){
		MyThread t1 = new MyThread();
		MyThread t2 = new MyThread();
		MyThread t3 = new MyThread();
		t1.start();
		t2.start();
		t3.start();
	}
}

执行一下,我们可以看到打印的hashCode(哈希码,对象实例的唯一标识,类似于我们每个人的身份证号码)是同一个值。以上场景便是立即加载的单例设计模式。

延迟加载(懒汉模式)

延迟加载:指在调用get()时候实例才被创建。

MyObject.java

package test;
public class MyObject{
  private static MyObject myObject;
  
  private MyObject(){
  }
  
  public static MyObject getInstance(){
  //延迟加载
  	if(myObject == null){
  		myObject = new MyObject();
  	}
    return myObject;
  }
} 

虽然“延迟加载”实现了单例设计模式,但在多线程的环境下,上面“延迟加载”的代码完全是错误的,根本不能保持单例的状态。

在这里插入图片描述
在这里插入图片描述

懒汉模式保证单例的解决方案

1. synchronized关键字实现

  • 锁getInstance()方法:运行效率低

  • 锁类(Object.class):运行效率低

  • 针对某部分重要的代码进行单独锁同步:还是存在一定的多线程安全隐患

  • 使用DCL双检查锁机制

    jjj
    在这里插入图片描述

2. 静态内置类实现单例模式

DCL可以解决多线程单例的安全问题;用其他的办法也能达到同样的效果。

在这里插入图片描述

3. 序列化和反序列化实现单例

静态内置类可以解决线程安全问题。可如果遇到序列化对象时,使用默认的方式运行,得到的结果还是多例的。

可以用以下的readResolve()方法解决

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. 使用static代码块实现单例

package test;
public class MyObject{
  private static MyObject instance = null;
  
  private MyObject(){}
  
  static{
    instance = new MyObject();
  }
  public static MyObject getInstance(){
    return instance;
  }
} 

jjjjjjj

5. 使用enum枚举实现单例

在这里插入图片描述

6. 完善使用enum实现单例模式

上面的示例将枚举类进行暴露,违反了“职责单一原则”,接下来可以进行完善

在这里插入图片描述

MyThread.java代码如下

package extthread;

public class MyThread extends Thread{
  @Override
  public void run(){
    for(int i=0; i< 5 ; i++){
      System.out.println(MyObject.getConnection().hashCode());
    }
  }
} 

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值