什么是Singleton
-
Singleton:在Java中即指单例设计模式,它是软件开发中最常用的设计模式之一。
-
单:唯一
-
例:实例
-
单例设计模式,即某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式。
-
例如:代表JVM运行环境的Runtime类
要点
- 一是某个类只能有一个实例;
构造器私有化 - 二是它必须自行创建这个实例;
含有一个该类的静态变量来保存这个唯一的实例 - 三是它必须自行向整个系统提供这个实例;
对外提供获取该实例对象的方式:
(1)直接暴露(2)用静态变量的get方法获取
几种常见形式
-
饿汉式:直接创建对象,不存在线程安全问题
直接实例化饿汉式(简洁直观)
枚举式(最简洁)
静态代码块饿汉式(适合复杂实例化) -
懒汉式:延迟创建对象
线程不安全(适用于单线程)
线程安全(适用于多线程)
静态内部类形式(适用于多线程)
饿汉式
直接实例化饿汉式
package com.liang.ji;
/**
* 饿汉式
* 在类初始化时直接创建实例对象,不管你是否需要这个对象都会创建
* 1)构造器私有化
* 2)自行创建,并且用静态变量保存
* 3)向外提供这个实例
* 4)强调这是一个单例,可以用final修饰
*/
public class Singleton {
public static final Singleton INSTANCE = new Singleton();
private Singleton() {
System.out.println("111");
}
}
测试:
package com.liang.ji;
public class Test1 {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
Singleton singleton1 = Singleton.INSTANCE;
}).start();
}
}
}
是线程安全的
枚举式
package com.liang.ji;
/*
* 枚举类型:表示该类型的对象是有限的几个
* 我们可以限定为一个,就成了单例
*/
public enum Singleton2 {
INSTANCE;
private Singleton2(){
System.out.println("构造方法");
}
}
测试:
package com.liang.ji;
public class Test1 {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
Singleton2 singleton = Singleton2.INSTANCE;
}).start();
}
}
}
线程安全
静态代码块饿汉式
package com.liang.ji;
import lombok.AllArgsConstructor;
import lombok.ToString;
@AllArgsConstructor //全参构造方法
@ToString //toString
public class Singleton3 {
public static Singleton3 INSTANCE;
static {
INSTANCE = new Singleton3("张亮","123456");
}
private Singleton3(){
System.out.println("执行了构造方法");
}
private String name;
private String password;
}
测试:
package com.liang.ji;
public class Test1 {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
Singleton3 singleton = Singleton3.INSTANCE;
System.out.println(singleton);
}).start();
}
}
}
线程安全
懒汉式
线程不安全
package com.liang.ji;
/*
* 懒汉式:
* 延迟创建这个实例对象
*
* (1)构造器私有化
* (2)用一个静态变量保存这个唯一的实例
* (3)提供一个静态方法,获取这个实例对象
*/
public class Singleton4 {
private static Singleton4 INSTANCE;
private Singleton4(){
System.out.println("执行了构造方法");
}
public static Singleton4 getINSTANCE(){
if (INSTANCE == null){
INSTANCE = new Singleton4();
}
return INSTANCE;
}
}
测试:
package com.liang.ji;
public class Test1 {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
Singleton4 singleton = Singleton4.getINSTANCE();
}).start();
}
}
}
单线程环境是线程安全的,多线程环境下是不安全的
线程安全
package com.liang.ji;
/*
* 懒汉式:
* 延迟创建这个实例对象
* (1)构造器私有化
* (2)用一个静态变量保存这个唯一的实例
* (3)提供一个静态方法,获取这个实例对象
*/
public class Singleton5 {
private volatile static Singleton5 INSTANCE; //多线程环境下使用volatile禁止指令重排
private Singleton5(){
System.out.println("执行了构造方法");
}
public static Singleton5 getINSTANCE(){
if (INSTANCE == null){
synchronized (Singleton5.class){
if (INSTANCE == null){
INSTANCE = new Singleton5();
}
}
}
return INSTANCE;
}
}
测试:
package com.liang.ji;
public class Test1 {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
Singleton5 singleton = Singleton5.getINSTANCE();
}).start();
}
}
}
线程安全
静态内部类形式
package com.liang.ji;
/*
* 在内部类被加载和初始化时,才创建INSTANCE实例对象
* 静态内部类不会自动随着外部类的加载和初始化而初始化,它是要单独去加载和初始化的。
* 因为是在内部类加载和初始化时,创建的,因此是线程安全的
*/
public class Singleton6 {
private Singleton6(){
System.out.println("构造方法");
}
private static class Inner{
private static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance(){
return Inner.INSTANCE;
}
}
测试:
package com.liang.ji;
public class Test1 {
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
Singleton6 singleton = Singleton6.getInstance();
}).start();
}
}
}
线程安全
小结
- 如果是饿汉式,枚举形式最简单
- 如果是懒汉式,静态内部类形式最简单