线程的单例模式
一、懒汉式线程单例模式
以下该实例是懒汉式的单例模式(线程不安全)
public class Singleton{
private static Singleton singleton;
private Singleton(){} //设置构造方法私有化
public static Singleton getInstance(){
if(singleton == null)
singleton = new Singleton();
return singleton;
}
}
当有多个线程同时访问,那么就会创建多个实例。因此我们可以通过加锁的方式进行升级。
public class Singleton{
private static Singleton singleton;
private Singleton(){} //设置构造方法私有化
public static synchronized Singleton getInstance(){
if(singleton == null)
singleton = new Singleton();
return singleton;
}
}
这样每次只允许一个线程调用该方法,那么就可以实现线程的安全性,但同时由于每次只允许一个线程访问,也导致效率极其低下。
因此,我们在对代码进行升级,加入双重检验锁,当实例为空时线程进入同步代码区域,其他线程阻塞。进入同步代码区的线程再次判断实例是否为空,如果为空则创建并返回。此时如果有阻塞的进程进入同步区但需要判断实例是否为空,不为空也就不会再创建新的对象。
双重检验锁模式(double checked locking pattern),是一种使用同步块加锁的方法。程序员称其为双重检查锁,因为会有两次检查 instance==null,一次是在同步块外,一次是在同步块内。为什么在同步块内还要再检验一次?因为可能会有多个线程一起进入同步块外的if,如果在同步块内不进行二次检验的话就会生成多个实例了。
public class Singleton{
private static Singleton singleton;
private Singleton(){} //设置构造方法私有化
public static Singleton getInstance(){
if(singleton == null){ //Single Checked
synchronized(Singleton.class){
if(singleton == null) //Double Checked
singleton = new Singleton();
}
}
return singleton;
}
}
二、 饿汉式线程(安全)单例模式
以下该实例是饿汉式的单例模式
public class Singleton {
private static Singleton singleton = new Singleton();
// 私有构造方法,保证外界无法直接实例化。
private Singleton() {}
// 通过公有的静态方法获取对象实例
public static Singleton getInstace() {
return singleton;
}
}
再补充一个更好的饿汉式的单例线程(静态内部类)
public class Singleton {
private static class SingletonCreater{
private static final Singleton singleton = new Singleton();
}
private Singleton(){}
public static final Singleton getInstance(){
return SingletonCreater.singleton;
}
}
饿汉式在线程还没出现之前就已经实例化了,所以饿汉式一定是线程安全的。
1.懒汉模式:顾名思义,他是一个懒汉,他不愿意动弹。什么时候需要吃饭了,他就什么时候开始想办法搞点食物。
即懒汉式一开始不会实例化,什么时候用就什么时候new,才进行实例化。
2.饿汉模式:顾名思义,他是一个饿汉,他很勤快就怕自己饿着。他总是先把食物准备好,什么时候需要吃了,他随时拿来吃,不需要临时去搞食物。
即饿汉式在一开始类加载的时候就已经实例化,并且创建单例对象,以后只管用即可。
区别 | 饿汉式 | 懒汉式 |
---|---|---|
实例化 | 一开始就实例化 | 等到要用的时候才实例化 |
线程安全 | 安全 | 不安全,需要加锁 |
性能 | 效率高 | 效率低 |
占用内存 | 浪费 | 不浪费 |