一、饿汉模式
当类被加载时,静态变量instance就会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建,不会出现创造多个单例对象的情况,可确保单例对象的唯一性,在单线程和多线程的情况下都可以保证正确性。
1)单线程
public class 单例模式之饿汉 {
//一开始就初始化
private static 单例模式之饿汉 instace = new 单例模式之饿汉();
private 单例模式之饿汉(){}
public static 单例模式之饿汉 getInstace() {
return instace;
}
public static void main(String[] args){
单例模式之饿汉 ins1 = 单例模式之饿汉.getInstace();
单例模式之饿汉 ins2 = 单例模式之饿汉.getInstace();
单例模式之饿汉 ins3 = 单例模式之饿汉.getInstace();
System.out.println(ins1 == ins2);
System.out.println(ins2 == ins3);
}
}
结果:
2)多线程
public class 单例模式之饿汉 {
//一开始就初始化
private static 单例模式之饿汉 instace = new 单例模式之饿汉();
private 单例模式之饿汉(){}
public static 单例模式之饿汉 getInstace() {
return instace;
}
static class MyThread extends Thread {
@Override
public void run() {
单例模式之饿汉 ins1 = 单例模式之饿汉.getInstace();
System.out.println(ins1);
}
}
public static void main(String[] args){
MyThread[] threads = new MyThread[20];
for(int i = 0; i < 10; i++) {
threads[i] = new MyThread();
}
for(int i = 0; i < 10; i++) {
threads[i].start();
}
}
}
结果:
二、懒汉模式
1)单线程
public class 单例模式之懒汉模式 {
private static 单例模式之懒汉模式 instance = null;
private 单例模式之懒汉模式() { }
public static 单例模式之懒汉模式 getInstance() {
if(instance == null) {
instance = new 单例模式之懒汉模式();
}
return instance;
}
public static void main(String[] args) {
单例模式之懒汉模式 ins1 = 单例模式之懒汉模式.getInstance();
单例模式之懒汉模式 ins2 = 单例模式之懒汉模式.getInstance();
单例模式之懒汉模式 ins3 = 单例模式之懒汉模式.getInstance();
System.out.println(ins1 == ins2);
System.out.println(ins2 == ins3);
}
}
结果:
2)多线程
private volatile static 单例模式之懒汉模式 instance = null;
private 单例模式之懒汉模式() { }
public static 单例模式之懒汉模式 getInstance() {
//第一次判断
if(instance == null) {
//内部枷锁
synchronized (单例模式之懒汉模式.class) {
//二次判断
if(instance == null) {
//会发生重排序问题
instance = new 单例模式之懒汉模式();
}
}
}
return instance;
}
static class MyThread extends Thread {
@Override
public void run() {
单例模式之懒汉模式 ins1 = 单例模式之懒汉模式.getInstance();
}
}
public static void main(String[] args) {
MyThread[] threads = new MyThread[10];
for(int i = 0; i < 10; i++) {
threads[i] = new MyThread();
}
for(int i = 0; i < 10; i++) {
threads[i].start();
}
}
}
注意:
- 加synchronized 可以防止重排序问题,内部枷锁可以提升效率
- 之所以进行二次判断是因为抢锁成功后后条件可能发生了变化,这样可以确保唯一实例
- instance = new 单例模式之懒汉模式();可能发生重排序问题,所以在创建静态变量instance时,在它前面加上volatile