一.介绍
保证某个类在程序中的实例只有一份, 该类只提供一个获得该实例的静态方法;
二. 单例模式的8种实现方式
- 饿汉式(静态常量)
- 饿汉式(静态代码块)
- 懒汉式(线程不安全)
- 懒汉式(线程安全, 同步方法)
- 懒汉式(线程安全, 同步代码块)
- Double-check双重检查
- 静态内部类方式
- 枚举方式
其中: 推荐使用1, 2, 6, 7, 8
三.代码示例
- 饿汉式(静态常量) [推荐]
/**
* 单例模式1: 饿汉式-静态变量方式, 资源浪费
*
* @author Lx
* @version 2019年11月26日 上午11:25:01
* @see com.lx.singleton.Singleton01
*
*/
public class Singleton01 {
// 构造私有化, 防止外部new
private Singleton01() {};
// 私有成员静态变量
private static final Singleton01 singleton = new Singleton01();
// 公有静态方法
public static Singleton01 getInstance(){
return singleton;
}
public static void main(String[] args) {
Singleton01 s1 = Singleton01.getInstance();
Singleton01 s2 = Singleton01.getInstance();
// true
System.out.println(s1==s2);
}
}
- 饿汉式(静态代码块)
/**
* 单例模式2: 饿汉式-静态代码块方式, 资源浪费
*
* @author Lx
* @version 2019年11月26日 上午11:25:01
* @see com.lx.singleton.Singleton02
*
*/
public class Singleton02 {
// 构造私有化, 防止外部new
private Singleton02() {};
// 私有成员静态变量
private static Singleton02 singleton;
static {
singleton = new Singleton02();
}
// 公有静态方法
public static Singleton02 getInstance(){
return singleton;
}
public static void main(String[] args) {
Singleton02 s1 = Singleton02.getInstance();
Singleton02 s2 = Singleton02.getInstance();
// true
System.out.println(s1==s2);
}
}
- 懒汉式(线程不安全)
/**
* 单例模式3: 懒汉式-线程不安全
*
* @author Lx
* @version 2019年11月26日 上午11:25:01
* @see com.lx.singleton.Singleton03
*
*/
public class Singleton03 {
// 构造私有化, 防止外部new
private Singleton03() {};
// 私有成员静态变量
private static Singleton03 singleton = null;
// 公有静态方法
public static Singleton03 getInstance(){
// 此处if判断线程不安全, 多个线程可能同时进if, 创建多次实例
if(singleton==null) {
singleton = new Singleton03();
}
return singleton;
}
public static void main(String[] args) {
Singleton03 s1 = Singleton03.getInstance();
Singleton03 s2 = Singleton03.getInstance();
// true
System.out.println(s1==s2);
}
}
- 懒汉式(线程安全, 同步方法)
/**
* 单例模式4: 懒汉式-同步方法线程安全, 效率低下
*
* @author Lx
* @version 2019年11月26日 上午11:25:01
* @see com.lx.singleton.Singleton04
*
*/
public class Singleton04 {
// 构造私有化, 防止外部new
private Singleton04() {};
// 私有成员静态变量
private static Singleton04 singleton = null;
// 公有静态方法
public static synchronized Singleton04 getInstance(){
// 此处if判断线程不安全, 多个线程可能同时进if, 创建多次实例
if(singleton==null) {
singleton = new Singleton04();
}
return singleton;
}
public static void main(String[] args) {
Singleton04 s1 = Singleton04.getInstance();
Singleton04 s2 = Singleton04.getInstance();
// true
System.out.println(s1==s2);
}
}
- 懒汉式(线程安全, 同步代码块)
/**
* 单例模式5: 懒汉式-同步代码块线程安全, 效率低下
*
* @author Lx
* @version 2019年11月26日 上午11:25:01
* @see com.lx.singleton.Singleton05
*
*/
public class Singleton05 {
// 构造私有化, 防止外部new
private Singleton05() {};
// 私有成员静态变量
private static Singleton05 singleton = null;
// 公有静态方法
public static Singleton05 getInstance(){
synchronized(Singleton05.class) {
if(singleton==null) {
singleton = new Singleton05();
}
}
return singleton;
}
public static void main(String[] args) {
Singleton05 s1 = Singleton05.getInstance();
Singleton05 s2 = Singleton05.getInstance();
// true
System.out.println(s1==s2);
}
}
- Double-check 双重检查
/**
* 单例模式1: 懒汉式-双重检查,线程安全高效, 推荐
*
* @author Lx
* @version 2019年11月26日 上午11:25:01
* @see com.lx.singleton.Singleton06
*
*/
public class Singleton06 {
// 构造私有化, 防止外部new
private Singleton06() {};
// 私有成员静态变量
private static Singleton06 singleton = null;
// 公有静态方法
public static Singleton06 getInstance(){
// 此处if判断线程不安全, 多个线程可能同时进if, 创建多次实例
if(singleton==null) {
synchronized (Singleton06.class) {
if(singleton==null) {
singleton = new Singleton06();
}
}
}
return singleton;
}
public static void main(String[] args) {
Singleton06 s1 = Singleton06.getInstance();
Singleton06 s2 = Singleton06.getInstance();
// true
System.out.println(s1==s2);
}
}
- 静态内部类方式
/**
* 单例模式7: 懒汉式-静态内部类方式, 懒加载, 安全, 推荐
* 1)此方式采用类装载机制来保证初始化实例时只有一个线程
* 2)静态内部类方式在Singleton类被加载时并不会立即实例化, 而是在需要实例化时, 调用getInstance方法才会装载GetSingleton07类,从而完成Singleton的实例化
* 3)类的静态属性只会在第一次加载类的时候初始化, 所以在这里, JVM帮助我们保证了线程的安全性, 在类进行初始化时, 别的线程是无法进入的
* 4)优点: 避免了线程不安全, 利用静态内部类特点实现延迟加载, 效率高
*
* @author Lx
* @version 2019年11月26日 上午11:25:01
* @see com.lx.singleton.Singleton07
*
*/
public class Singleton07 {
// 构造私有化, 防止外部new
private Singleton07() {};
private static class GetSingleton07 {
private static final Singleton07 SINGLETON = new Singleton07();
}
public static synchronized Singleton07 getInstance() {
return GetSingleton07.SINGLETON;
}
public static void main(String[] args) {
Singleton07 s1 = Singleton07.getInstance();
Singleton07 s2 = Singleton07.getInstance();
// true
System.out.println(s1==s2);
}
}
- 枚举方式
/**
* 单例模式08: 枚举方式-线程安全, 高效, 推荐
*
* @author Lx
* @version 2019年11月26日 下午2:49:38
* @see com.lx.singleton.Singleton08
*
*/
public enum Singleton08 {
INSTANCE;
}
四. JDK中的单例模式
java.lang包下的Runtime类就是单例中的饿汉式.
里面有几个很有意思的方法: