4-1.单例模式
单例模式创建的8种写法:
1.饿汉式(静态常量)
2.饿汉式(静态代码块)
3.懒汉式(新城不安全)
4.懒汉式(线程安全,同步方法)
5.懒汉式(线程安全,同步代码块)
6.双重检索
7.静态内部类
8.枚举
1.饿汉式(静态常量)
步骤:
1.构造器私有化(防止new对象)
2.类的内部创建对象
3.向外暴露一个静态的公共方法
public class SingleTest1 {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2);
}
}
class Singleton {
//1.构造器私有化,防止外部new
private Singleton() {
}
//2.本类中直接创建出实例
private final static Singleton instance = new Singleton();
//3.提供共有的方法获取该单例对象
public static Singleton getInstance() {
return instance;
}
}
2.饿汉式(静态代码块)
public class SingleTest1 {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2);
}
}
class Singleton {
//1.构造器私有化,防止外部new
private Singleton() {
}
private final static Singleton instance;
//2.静态代码块创建出实例
static {
instance = new Singleton();
}
//3.提供共有的方法获取该单例对象
public static Singleton getInstance() {
return instance;
}
}
3.懒汉式(线程不安全)
public class SingleTest1 {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2);
}
}
class Singleton {
//1.构造器私有化,防止外部new
private Singleton() {
}
private static Singleton instance;
//3.提供共有的方法获取该单例对象
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
4.懒汉式(线程安全,同步方法)
public class SingleTest1 {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2);
}
}
class Singleton {
//1.构造器私有化,防止外部new
private Singleton() {
}
private static Singleton instance;
//3.提供共有的方法获取该单例对象
//加锁解决线程安全问题
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
5.懒汉式(有问题,不能写)
class Singleton {
//1.构造器私有化,防止外部new
private Singleton() {
}
private static Singleton instance;
//3.提供共有的方法获取该单例对象
public static Singleton getInstance() {
if (instance == null) {
//当a线程拿到锁,b线程刚执行到这里时阻塞,a线程执行完毕,b线程不会再次判断而会直接进入到加锁代码块中,无法保证单例
synchronized (Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
6.双重检查(DCL)
class Singleton {
//1.构造器私有化,防止外部new
private Singleton() {
}
//2.加volatile保证线程可见性,禁止指令重排问题
private static volatile Singleton instance;
//3.提供共有的方法获取该单例对象
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
//再加一次判断,解决上个例子的判断问题
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
7.静态内部类
class Singleton {
private Singleton() {
}
//1.定义一个静态内部类
//注意:
//1.当Singleton被装载时,静态内部类SingletonInstance是不会被装载的,因为jvm是按需加载
//2.当调用getInstance方法时,类加载器会加载SingletonInstance的内部类,而且只加载一遍,是线程安全的
//从而达到懒加载并且线程安全问题!
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
8.枚举
public class SingleTest1 {
public static void main(String[] args) {
Singleton singleton1 = Singleton.INSTANCE;
Singleton singleton2 = Singleton.INSTANCE;
System.out.println(singleton1 == singleton2);
}
}
enum Singleton{
INSTANCE;
}
单例模式在JDK应用的源码分析
1.我们jdk中,java.lang.Runtime就是经典的单例模式:饿汉式
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
...
}