java实现线程安全的单例模式

本文介绍了如何在Java中实现线程安全的单例模式,从经典实现到处理多线程问题,再到优化方案,如急切创建和双重检查加锁。讨论了在多线程环境下,如何保证单例的唯一性和性能效率。
摘要由CSDN通过智能技术生成

以下是自己从别的博客上看来的,自己又重写了一下,加深印象。

1.经典单例模式实现

<span style="font-size:12px;">//线程不安全</span>
<span style="font-size:12px;">public class Singleton {    
      //用一个静态变量来记录Singleton类的唯一实例   
      private static Singleton uniqueInstance;   
    
      private Singleton() {}   
           
      //注意这个方法也是静态的   
      public static Singleton getInstance() {    
           if(uniqueInstance == null) {   
             uniqueInstance = new Singleton();   
           }   
           return uniqueInstance;   
      }   
}  </span>


单例常被用来管理共享的资源,例如数据库连接、线程池、缓存、注册表。

单例模式确保一个类只有一个实例,并提供一个全局访问点。

这个模式的问题:在多线程时,并不能保证这个类只被实例化一次。

2.处理多线程

    //用一个静态变量来记录Singleton类的唯一实例  
    private static Singleton uniqueInstance;  
    private Singleton() {}  
    //注意这个方法也是静态的  
    public static synchronized Singleton getInstance() {   
        if(uniqueInstance == null) {  
             uniqueInstance = new Singleton();  
         }  
         return uniqueInstance;  
    }  
}  

  通过增加synchronized关键字到getInstance()方法中,迫使每个线程在进入方法之前,要先等别的线程离开该方法。也就是说,不会有两个线程可以同时进入这个方法。

    这种方法存在的问题:只有第一次执行此方法时,才真正需要同步。换句话说,一旦设置好uniqueInstance变量,就不再需要同步这个方法了。之后每次调用这个方法,同步都是一种浪费。

3.改善多线程

3.1 如果getInstance()的性能对应用程序不是很关键,就不用优化了

3.2 使用急切创建实例,而不用延迟实例化的做法

public class Singleton {   
  
    private static Singleton uniqueInstance = new Singleton();
    private Singleton() {}  
    public static Singleton getInstance() {   
         return uniqueInstance;  
    }  
}  

语句在静态初始化器(static initializer)中创建单例,这保证了线程安全。

  利用这个做法,JVM在加载这个类时马上创建此唯一的单件实例。JVM保证任何线程访问uniqueInstance静态变量之前,一定先创建些实例。

3.3 用“双重检查加锁”,在getInstance()中减少使用同步 

    首先检查实例是否已经创建,如果尚未创建,才进行同步。这样一来,只有第一次会同步,这正是我们想要的。

public class Singleton {    
    private volatile static Singleton uniqueInstance;   
    private Singleton() {}
    public static Singleton getInstance() {    
    if(uniqueInstance == null) { //(1)   
       //只有第一次才彻底执行这里的代码   
       synchronized() {   
          //再检查一次   
          if(uniqueInstance == null)   
<span style="white-space:pre">	</span>  <span style="white-space:pre">	</span>uniqueInstance = new Singleton();   
       }   
    }   
         return uniqueInstance;   
    }   
}  

在最开始如果有1、2、3个线程走到了(1)处,假设1进入了同步块,2、3等待。1实例化后,2进入同步块,发现uniqueInstance已经不为空,跳出同步块。接着3进入,又跳出同步块。

volatile关键字确保:当uniqueInstance变量被初始化成Singleton实例时,多个线程正确地uniqueInstance变量。如果性能是你关心的重点,那么这个做法可以帮你大大地减少getInstance()的时间耗费。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值