8种方式实现单例模式
1、饿汉式的两种写法
饿汉式的特点:在获取单例对象之前对象就已经创建完成了。
package com.JUC编程.volatile0;
public class SingleEh {
//饿汉式单例模式
//1.静态常量
/* private static final SingleEh singleEh=new SingleEh();
private SingleEh(){
}
public static SingleEh getSingleEh(){
return singleEh;
}*/
//2.静态代码块
private static final SingleEh singleEh;
private SingleEh(){
}
static {
singleEh=new SingleEh();
}
public static SingleEh getSingleEh(){
return singleEh;
}
}
class test{
public static void main(String[] args) {
SingleEh singleEh = SingleEh.getSingleEh();
SingleEh singleEh1 = SingleEh.getSingleEh();
System.out.println(singleEh1 == singleEh);//true
}
}
2、懒汉单例的四种写法
懒汉单例的特点:在真正需要单例的时候才创建出该对象。
package com.JUC编程.volatile0;
public class SingleLh {
//懒汉式单例模式
//1.线程不安全
private SingleLh(){
}
private static SingleLh singleLh;//定义的时候不初始化
public static SingleLh getSingleLh(){
//当有两个线程同时进入到这个方法中时,就会发生线程安全问题
if (singleLh==null) {
return new SingleLh();
}
return singleLh;
}
}
package com.JUC编程.volatile0;
public class SingleLh {
//2.使用synchronized修饰方法,但是性能太低
private SingleLh(){
}
private static SingleLh singleLh;
public synchronized static SingleLh getSingleLh(){
if (singleLh==null) {
return new SingleLh();
}
return singleLh;
}
}
package com.JUC编程.volatile0;
public class SingleLh {
//3.可以缩小synchronized的使用范围,但是我们发现却保证不了线程安全
private SingleLh(){
}
private static SingleLh singleLh;
public synchronized static SingleLh getSingleLh(){
if (singleLh==null) {
synchronized (SingleLh.class) {
return new SingleLh();
}
}
return singleLh;
}
}
volatile双重检查机制(推荐方式)
package com.JUC编程.volatile0;
public class SingleLh {
//4.volatile双重检查模式(推荐)
private SingleLh(){
}
//volatile在此处主要的作用是保证可见性和禁止指令重排序
private volatile static SingleLh singleLh;
public static SingleLh getSingleLh(){
/*双重检查既保证了效率又保证了线程安全*/
if (singleLh==null) {
synchronized (SingleLh.class) {
if(singleLh==null) {
//因为new SingleLh()并不是一个原子操作,可能会发生指令重排。
return new SingleLh();
}
}
}
return singleLh;
}
}
3、静态内部类单例方式
静态内部类是在被调用时才会被加载,这种方案实现了懒汉单例的一种思想,需要用到的时候才会去创建单例,加上JVM的特性,这种方式又实现了线程安全的创建单例对象。
package com.JUC编程.volatile0;
public class SingleStatic {
/*步骤:
* 1.提供一个静态内部类来,里面提供一个常量用来存储单例对象
* 2.提供一个静态方法返回静态内部类中的单例对象
* */
private SingleStatic(){
}
private static class InnerClass{
private static final SingleStatic single=new SingleStatic();
}
public static SingleStatic getSingleStatic(){
return InnerClass.single;
}
}
4、枚举实现单例
package com.JUC编程.volatile0;
/*
* 枚举实际上是一种多例的模式,如果我们直接定义了一个实例就相当于是单例了
* */
public enum SingleEnum {
//但是枚举的主要作用是用于信息的标志和分类,不足以应付特殊的应用场景,单例中用的较少
SINGLE_ENUM;
}