在实际开发中,当我们要求一个类只能被实例化一次时,比如各种各样的Manager、各种各样的Factory,可以使用单例模式
饿汉模式
public class SingleInstance01 {
private static final SingleInstance01 INSTANCE = new SingleInstance01();
private SingleInstance01() {}
public static SingleInstance01 getInstance() {
return INSTANCE;
}
}
public class Main {
public static void main(String[] args) {
SingleInstance01 s1 = SingleInstance01.getInstance();
SingleInstance01 s2 = SingleInstance01.getInstance();
System.out.println(s1 == s2);//输出true
}
}
类加载到内存后,就会创建一个实例对象
由JVM保证线程安全
JVM保证每一个class只会被load到内存一次,static的变量是在class被load到内存之后,会马上进行实例化,所以也保证了INSTANCE只会被初始化一次
缺点是:不管用到与否,类加载时就会完成实例化
懒汉模式
public class SingleInstance02 {
private static SingleInstance02 INSTANCE;
private SingleInstance02() {}
public static SingleInstance02 getInstance() {
if(INSTANCE == null) {
doSomeThings();
INSTANCE = new SingleInstance02();
}
return INSTANCE;
}
private static void doSomeThings() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(SingleInstance02.getInstance().toString());
}
}).start();
}
}
}
/*************************** 输出结果 *******************************
com.gale.designpattern.singleinstance.SingleInstance02@3a2cad68
com.gale.designpattern.singleinstance.SingleInstance02@48ac2be5
com.gale.designpattern.singleinstance.SingleInstance02@48ac2be5
com.gale.designpattern.singleinstance.SingleInstance02@4e35792a
com.gale.designpattern.singleinstance.SingleInstance02@2cb30bd3
com.gale.designpattern.singleinstance.SingleInstance02@11d32fc4
com.gale.designpattern.singleinstance.SingleInstance02@d084795
com.gale.designpattern.singleinstance.SingleInstance02@48ac2be5
com.gale.designpattern.singleinstance.SingleInstance02@48ac2be5
com.gale.designpattern.singleinstance.SingleInstance02@48ac2be5
******************************************************************/
虽然达到了按需初始化的目的,却带来了线程不安全的问题
在懒汉模式的基础上,通过synchronized锁定类的class对象解决线程不安全的问题,也叫做线程安全的懒汉模式,但也带来了效率上的下降
public class SingleInstance03 {
private static SingleInstance03 INSTANCE;
private SingleInstance03() {}
public static synchronized SingleInstance03 getInstance() {
if(INSTANCE == null) {
doSomeThings();
INSTANCE = new SingleInstance03();
}
return INSTANCE;
}
private static void doSomeThings() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(SingleInstance03.getInstance().toString());
}
}).start();
}
}
}
/*************************** 输出结果 *******************************
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
com.gale.designpattern.singleinstance.SingleInstance03@1469c295
******************************************************************/
试图通过减小同步代码块的方式来提高效率,不可行
public class SingleInstance04 {
private static SingleInstance04 INSTANCE;
private SingleInstance04() {}
public static SingleInstance04 getInstance() {
if(INSTANCE == null) {
synchronized (SingleInstance04.class) {
doSomeThings();
INSTANCE = new SingleInstance04();
}
}
return INSTANCE;
}
private static void doSomeThings() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(SingleInstance04.getInstance().toString());
}
}).start();
}
}
}
/*************************** 输出结果 *******************************
com.gale.designpattern.singleinstance.SingleInstance04@1ca5fe10
com.gale.designpattern.singleinstance.SingleInstance04@1ca5fe10
com.gale.designpattern.singleinstance.SingleInstance04@1ca5fe10
com.gale.designpattern.singleinstance.SingleInstance04@1ca5fe10
com.gale.designpattern.singleinstance.SingleInstance04@21b39199
com.gale.designpattern.singleinstance.SingleInstance04@6fd8b67a
com.gale.designpattern.singleinstance.SingleInstance04@b6f008f
com.gale.designpattern.singleinstance.SingleInstance04@18f3035c
com.gale.designpattern.singleinstance.SingleInstance04@8fddaf1
com.gale.designpattern.singleinstance.SingleInstance04@1dce2a4
******************************************************************/
双重检查的synchronized单例写法
public class SingleInstance05 {
private static SingleInstance05 INSTANCE;
private SingleInstance05() {}
public static SingleInstance05 getInstance() {
if(INSTANCE == null) {
synchronized (SingleInstance05.class) {
if(INSTANCE == null) {
doSomeThings();
INSTANCE = new SingleInstance05();
}
}
}
return INSTANCE;
}
private static void doSomeThings() {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(SingleInstance05.getInstance().toString());
}
}).start();
}
}
}
/*************************** 输出结果 *******************************
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
com.gale.designpattern.singleinstance.SingleInstance05@7dcec037
******************************************************************/
静态内部类的单例写法(最完美的写法之一)
public class SingleInstance06 {
private SingleInstance06() {
}
private static class SingleInstance06Holder {
private static final SingleInstance06 INSTANCE = new SingleInstance06();
}
public static SingleInstance06 getInstance() {
return SingleInstance06Holder. INSTANCE;
}
}
public class Main {
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(SingleInstance06.getInstance().toString());
}
}).start();
}
}
}
/*************************** 输出结果 *******************************
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
com.gale.designpattern.singleinstance.SingleInstance06@418b0eca
******************************************************************/
由JVM保证单例和线程安全
加载外部类时不会加载内部类,而是在getInstance方法被调用时,内部类才会被加载,这样就实现了懒加载
枚举单例:不仅可以解决线程同步,还可以防止反序列化(因为枚举类没有构造方法,即使反序列化后,也不能被实例化)(最完美的写法之一)
public enum SingleInstance07 {
INSTANCE;
public static SingleInstance07 getInstance() {
return INSTANCE;
}
}
public class Main {
public static void main(String[] args) {
for(int i=0; i<10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(SingleInstance07.getInstance().hashCode());
}
}).start();
}
}
}
/*************************** 输出结果 *******************************
1467106563
1467106563
1467106563
1467106563
1467106563
1467106563
1467106563
1467106563
1467106563
1467106563
******************************************************************/