设计模式——单例模式
概念:单例模式设计(SingleTon)得到一个单一的类,该类负责创建自己的对象,同时保证只有单个对象被创建,这个类提供了唯一访问对象的方法,可以直接访问,不需要实例化对象。
实现
1、私有的静态的当前类对象作为属性。
2、私有的构造方法。
3、公有的静态方法返回当前类对象。
分为两种方式:一直是饿汉式;另外一种是懒汉式。
饿汉式
/**
* 饿汉式单例模式
* 在静态元素加载时就创建了对象
* 共有方法调用就直接返回
* 线程安全
*/
public class SingleTon {
//私有的静态的当前类作为属性
private static SingleTon singleTon = new SingleTon();
//私有的构造方法
private SingleTon(){}
//提供共有的方法访问当前类实例
public static SingleTon getSingleTon(){
return singleTon;
}
}
懒汉式
1、这种没有加锁的懒汉式单例模式是非线程安全的,例如:多个线程同时访问单例对象的公有方法,它们同时判断对象为空,同时都会创建实例对象。
/**
* 懒汉式单例模式
* 当调用到静态公有方法时,才会创建对象
* 线程不安全,若在方法上加上synchronized,线程安全
*/
public class SingleTon {
//私有的静态的当前类作为属性
private static SingleTon singleTon;
//私有的构造方法
private SingleTon(){}
//提供共有的方法访问当前类实例
public static SingleTon getSingleTon(){
if (singleTon == null){
singleTon = new SingleTon();
}
return singleTon;
}
}
下面是单例模式的线程安全写法:
/**
* 单例模式 懒汉式-双重检查 + 对类加锁
*/
public class SingleTon {
private static volatile TestSingleton singleTon;
private SingleTon() {}
public static SingleTon getInstance() {
//第一次判断
if (singleTon == null) {
synchronized (SingleTon.class) {
//第二次判断
if (singleTon == null) {
singleTon = new SingleTon();
}
}
}
return singleTon;
}
}
分析一下这段代码,分析之前,大家应该知道synchronized关键字的用法。
当多个线程同时访问公有方法获取实例对象时,都能进入到第一次判断,进去之后,只能有一个线程能够获取到对象锁,获取到对象锁的那个线程进入第二次判断区创建实例对象,第一个获取对象锁的线程执行完同步代码块之后,释放对象锁,接下来获取对象锁的线程,就无法进入第二次判断里的代码块,因为此时实例对象已经不为空了,所以直接返回实例对象。
很多人可能疑问为什么要加volatile,是因为第一次判断的语句是在同步代码块之外的,无法保证它的有序性与可见性,因此需要加volatile关键字。