单例模式
单例模式:一个类只能有一个实例化对象,多个线程共享该实例对象的资源;要求:
外部不能随意调用构造函数创建对象;
私有化构造器
内部对外提供一个可调用的 public 函数,通过该函数获取单例对象;
这个方法要定义为 static,因为构造函数为私有,外部不能通过创建实例对象来调用该方法,只能定义为静态,通过类调用
最基本思想,单线程下实现单例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class SingletonDemo {
private static SingletonDemo singletonDemo = null;
private SingletonDemo() { System.out.println("创建了SingletonDemo对象"); }
public static SingletonDemo getInstance() { if (singletonDemo == null) { singletonDemo = new SingletonDemo(); } return singletonDemo; } }
|
多线程下,对 public 方法加锁,使同一时间只有一个线程能访问该资源:
1 2 3 4 5 6
| public synchronized static SingletonDemo getInstance() { if (singletonDemo == null) { singletonDemo = new SingletonDemo(); } return singletonDemo; }
|
也可以锁定其他共享资源,如代码块、类等;更推荐锁代码块,因为影响同步的代码可能不是整个方法,更细粒度的锁灵活性较高。
1 2 3 4 5 6 7 8
| public static SingletonDemo getInstance() { synchronized (SingletonDemo.class) { if (singletonDemo == null) { singletonDemo = new SingletonDemo(); } } return singletonDemo; }
|
注:应先锁,再判空;先判空,会有多个线程进入创建对象的代码块等待资源。
更加安全,使用 double check,双重校验锁:
1 2 3 4 5 6 7 8 9 10
| public static SingletonDemo getInstance() { if (singletonDemo == null) { synchronized (SingletonDemo.class) { if (singletonDemo == null) { singletonDemo = new SingletonDemo(); } } } return singletonDemo; }
|
绝对安全,定义对象时加上 volatile 关键字:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class SingletonDemo {
private volatile static SingletonDemo singletonDemo = null;
private SingletonDemo() { System.out.println("创建了SingletonDemo对象"); }
public static SingletonDemo getInstance() { if (singletonDemo == null) { synchronized (SingletonDemo.class) { if (singletonDemo == null) { singletonDemo = new SingletonDemo(); } } } return singletonDemo; } }
|
volatile 的作用:使内存中的数据对线程可见
一个线程在访问内存数据时,拿到的不是数据本身,而是将主内存中的东西复制保存在工作内存,相当于对内存中数据的副本进行操作,操作完成后再将数据保存到主内存;即主内存对线程是不可见的