完美解决单例设计模式中懒汉式线程安全的问题

作者:jingxian 时间:2021-12-30 01:54:21 

首先写个单例:


public class SingleDemo {
 private static SingleDemo s = null;
 private SingleDemo(){}
 public static SingleDemo getInstance(){
   if(s == null){
     s = new SingleDemo();
   }
   return s;
 }
}

写个测试类:


public class ThreadDemo3 {

public static void main(String[] args) {
   SingleDemo s1 = SingleDemo.getInstance();
   SingleDemo s2 = SingleDemo.getInstance();
   System.out.println(s2 == s2);
 }
}

运行结果一直都是true,说明单线程下是没问题的,下面写个多线程来访问单例


public class ThreadTest implements Runnable {
 //存放单例对象,使用Set是为了不存放重复元素
 public Set<SingleDemo> singles = new HashSet<SingleDemo>();
 @Override
 public void run() {
   //获取单例
   SingleDemo s = SingleDemo.getInstance();
   //添加单例
   singles.add(s);
 }
}

使用多线程并发访问单例:


public class ThreadDemo3 {

public static void main(String[] args) {
//   SingleDemo s1 = SingleDemo.getInstance();
//   SingleDemo s2 = SingleDemo.getInstance();
//   System.out.println(s2 == s2);
   ThreadTest t = new ThreadTest();
   new Thread(t).start();
   new Thread(t).start();
   new Thread(t).start();
   new Thread(t).start();
   new Thread(t).start();
   new Thread(t).start();
   new Thread(t).start();
   new Thread(t).start();
   System.out.println(t.singles);
 }
}


运行结果如下:
[com.persagy.thread.SingleDemo@1bc4459, com.persagy.thread.SingleDemo@150bd4d]

[com.persagy.thread.SingleDemo@12b6651]

说明有线程并发访问安全问题,获取的不一定都是同一个实例

如何解决线程安全问题呢?

当然使用同步锁机制了啊

下面改进单例:


public class SingleDemo {
private static SingleDemo s = null;
private SingleDemo(){}
public static synchronized SingleDemo getInstance(){
if(s == null){
s = new SingleDemo();
}
return s;
}
}

加入同步函数后线程安全问题解决了

运行多次都是获取同一个实例,不会出现2个实例的情况了

[com.persagy.thread.SingleDemo@12b6651]

但是在多线程并发访问的情况下,每个线程每次获取实例都要判断下锁,效率比较低,为了提高效率,我加入了双重判断的方法,解决了效率的问题

代码如下:


public class SingleDemo {
private static SingleDemo s = null;
private SingleDemo(){}
public static SingleDemo getInstance(){
/*如果第一个线程获取到了单例的实例对象,
* 后面的线程再获取实例的时候不需要进入同步代码块中了*/
if(s == null){
//同步代码块用的锁是单例的字节码文件对象,且只能用这个锁
synchronized(SingleDemo.class){
if(s == null){
s = new SingleDemo();
}
}
}
return s;
}
}

用这种方式解决了懒汉式的线程安全问题,也提高了效率,但是在实际开发中还是用饿汉式的比较多,毕竟这个代码比较多,比较繁琐。

标签:单例设计模式,懒汉式
0
投稿

猜你喜欢

  • Spring AOP底层原理及代理模式

    2023-05-05 14:19:38
  • java冷知识:javac AbstractProcessor详解

    2022-08-01 19:32:09
  • spring cache注解@Cacheable缓存穿透详解

    2023-12-23 13:41:25
  • Android超清晰6.0权限申请AndPermission

    2023-08-05 10:52:26
  • 解决@RequestBody部分属性丢失的问题

    2023-08-01 15:00:21
  • 将JavaDoc注释生成API文档的操作

    2023-06-16 18:24:06
  • jvm调优的几种场景(小结)

    2023-04-11 18:37:04
  • java连接sql server 2008数据库代码

    2023-05-27 10:40:01
  • 如何安装java的运行环境IDEA

    2022-09-20 10:42:38
  • 详解java 三种调用机制(同步、回调、异步)

    2023-11-25 07:59:57
  • java文件操作输入输出结构详解

    2023-07-30 21:48:30
  • c#入门之类型转换详解

    2022-03-17 01:36:52
  • 解决mybatis-generator生成器添加类注释方法无效的问题

    2023-12-05 06:34:57
  • 三种Java自定义DNS解析器方法与实践

    2022-01-13 10:12:11
  • MyBatis-plus中的模糊查询解读

    2022-06-16 08:27:03
  • Java设计模式之享元模式示例详解

    2022-12-08 22:19:46
  • SpringBoot在Controller层接收参数的n种姿势(超详细)

    2023-01-28 00:54:39
  • Java overload和override的区别分析

    2023-10-12 15:16:17
  • Spring Retry 重试实例详解

    2021-07-15 22:43:26
  • 一文搞懂Java创建线程的五种方法

    2023-10-30 18:35:04
  • asp之家 软件编程 m.aspxhome.com