单例模式:确保一个类只有一个实例,自行实例化并向系统提供这个实例。
/**
* 线程不安全方式。
*/
public class Singleton {
private static Singleton singleton;
//防止外部类实现
private Singleton() {
}
public static Singleton getInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
我们用两个线程测试该单例模式的安全性:
public class SingleThread implements Runnable{
@Override
public void run() {
Singleton singleton=Singleton.getInstance();
System.out.println(singleton);
}
}
public class TestA {
public static void main(String[] args) {
Thread t1=new Thread(new SingleThread());
Thread t2=new Thread(new SingleThread());
t1.start();
t2.start();
}
}
结果分析:
当线程t1执行到if(singleton==null)时,去创建对象,但是对象并未创建好时,t2也同时执行到if语句。此时的singleton为null,t2也去new这个对象,因此这两个对象不是用一个。
饿汉式单例:
public class EagerSingleton {
private static final EagerSingleton single=new EagerSingleton();
private EagerSingleton(){
}
public static EagerSingleton getInstance(){
return single;
}
}
缺点:不能实现延迟加载。在类初始化时single对象就会被初始化。
懒汉式单例模式:
public class LazySingleton {
private static LazySingleton singleton=null;
private LazySingleton() {
}
public synchronized static LazySingleton getInstance(){
if(singleton==null){
singleton=new LazySingleton();
}
return singleton;
}
}
缺点:对于多线程状态下,我们每个线程执行时都要等待上一个线程释放这个锁。我们只需对创建这个对象时加锁就行
public class LazySingleton {
private static LazySingleton singleton=null;
private LazySingleton() {
}
public synchronized static LazySingleton getInstance(){
if(singleton==null){
synchronized(LazySingleton.class) {
singleton = new LazySingleton();
}
}
return singleton;
}
}
缺点:这个是线程非安全的。当线程1进入到该同步代码块中,1执行完,2进入到代码块,此时2线程并不知道1已经创建好,于是又创建线程。
因此我们可以采用双重检查锁定来实现:
public class LazySingleton {
private volatile static LazySingleton singleton=null;
private LazySingleton() {
}
public synchronized static LazySingleton getInstance(){
//第一次判断
if(singleton==null){
synchronized(LazySingleton.class) {
//第二次判断
if(singleton==null) {
singleton = new LazySingleton();
}
}
}
return singleton;
}
}