最近复习了下单例模式写法,记录下来,分析每种优缺点
其中标红的是推荐方式,有双重检查模式,还有枚举模式
1.饿汉式 静态变量方式(可用)
* 优点:编写简单 不存在并发问题 多个线程创建多个实例
* 缺点:一开始就加载,浪费资源.
/**
* @author: xuxu
* @date 2020/2/2 16:08
* @Description: 第一种单例模式写法
* 饿汉式 静态变量方式(可用)
* 优点:编写简单 不存在并发问题 多个线程创建多个实例
* 缺点:一开始就加载,浪费资源.
*/
public class Singleton01 {
private static Singleton01 INSTANCE = new Singleton01();
private Singleton01(){};
public static Singleton01 instance(){
return INSTANCE;
}
//测试
public static void main(String[] args) {
System.out.println(Singleton01.instance());
System.out.println(Singleton01.instance());
}
}
2.饿汉式 静态块模式(可用)
优点缺点和第一种类似 只是写法不同
/**
* @author: xuxu
* @date 2020/2/2 16:12
* @Description: 第二种单例模式创建方式
* 饿汉式 静态块模式(可用)
* 优点缺点和第一种类似 只是写法不同
*/
public class Singleton02 {
private static Singleton02 INSTANCE;
//静态块中创建
static{
INSTANCE = new Singleton02();
}
private Singleton02 (){
}
public static Singleton02 instance(){
return INSTANCE;
}
public static void main(String[] args) {
System.out.println(Singleton02.instance());
System.out.println(Singleton02.instance());
}
}
3.懒汉式 (不可用)
* 优点:懒加载,节省内存 使用时才实例化
* 缺点:存在线程安全问题,如果多个线程同时创建 很有可能出现同时判断INSTANCE为空 然后创建多个实例的情况
/**
* @author: xuxu
* @date 2020/2/2 16:16
* @Description:
*
* 第三种方式
* 懒汉式 (不可用)
* 优点:懒加载,节省内存 使用时才实例化
* 缺点:存在线程安全问题,如果多个线程同时创建 很有可能出现同时判断INSTANCE为空 然后创建多个实例的情况
*/
public class Singleton03 {
private static Singleton03 INSTANCE;
private Singleton03(){};
public static Singleton03 instance(){
if(INSTANCE==null){
INSTANCE = new Singleton03();
}
return INSTANCE;
}
}
4.懒汉式 同步锁(可用)
* 优点:懒加载,用synchronized关键字修饰 避免线程安全问题
* 缺点:每次调用该方式获取实例都会加锁,性能上有影响
/**
* @author: xuxu
* @date 2020/2/2 16:20
* @Description:
* 第4种创建方式 懒汉式 同步锁(可用)
* 优点:懒加载,用synchronized关键字修饰 避免线程安全问题
* 缺点:每次调用该方式获取实例都会加锁,性能上有影响
*/
public class Singleton04 {
private static Singleton04 INSTANCE;
private Singleton04(){};
public static synchronized Singleton04 instance(){
if(INSTANCE==null){
INSTANCE = new Singleton04();
}
return INSTANCE;
}
}
5.懒汉式 同步锁(不可用)
* 优点:懒加载,每次调用该方式获取实例前先判断是否实例已经存在,不存在才加锁
* 缺点:虽然创建时加了锁,但是前面的判断同样存在并发问题 比如两个线程都通过了判断.然后再获取锁
/**
* @author: xuxu
* @date 2020/2/2 16:20
* @Description:
* 第5种创建方式 懒汉式 同步锁(不可用)
* 优点:懒加载,每次调用该方式获取实例前先判断是否实例已经存在,不存在才加锁
* 缺点:虽然创建时加了锁,但是前面的判断同样存在并发问题 比如两个线程都通过了判断.然后再获取锁
*/
public class Singleton05 {
private static Singleton05 INSTANCE;
private Singleton05(){};
public static Singleton05 instance(){
if(INSTANCE==null){
synchronized(Singleton05.class){
INSTANCE = new Singleton05();
}
}
return INSTANCE;
}
}
6.懒汉式 双重检查模式 (面试时推荐用)
* 优点:懒加载,不存在线程安全问题
* 缺点:编写代码复杂,volatile容易遗漏
/**
* @author: xuxu
* @date 2020/2/2 16:20
* @Description:
* 第6种创建方式 懒汉式 双重检查模式 (面试时推荐用)
* 优点:懒加载,不存在线程安全问题
* 缺点:编写代码复杂,volatile容易遗漏
*/
public class Singleton06 {
//这里强调必须要加volatile
// 避免new Singleton06()创建对象时出现指令重排.
// 创建对象分3步,1.创建空对象,内存中分配地址 2.对象初始化赋值 3.对象实例指向对象引用. 这3部可能发生重排序
// 导致13步先执行,导致实际返回的INSTANCE内部属性没有初始化
private volatile static Singleton06 INSTANCE;
private Singleton06(){};
public static Singleton06 instance(){
if(INSTANCE==null){
synchronized(Singleton06.class){
//第二次检查,避免上一次判断存在线程安全问题.
if(INSTANCE==null){
INSTANCE = new Singleton06();
}
}
}
return INSTANCE;
}
}
7.静态内部类方式(可用)
/**
* @author: xuxu
* @date 2020/2/2 16:20
* @Description:
* 第7种创建方式 静态内部类方式(可用)
* 内部类的特点:
* 1.只能在内部类中定义静态类
* 2.静态内部类与外层类绑定,即使没有创建外层类的对象,它一样存在。
* 3.静态类的方法可以是静态的方法也可以是非静态的方法,静态的方法可以在外层通过静态类调用,而非静态的方法必须要创建类的对象之后才能调用。
* 5.只能引用外部类的static成员变量(也就是类变量)。
* 6.如果一个内部类不是被定义成静态内部类,那么在定义成员变量或者成员方法的时候,是不能够被定义成静态的。
* 优点:
* 缺点:
*/
public class Singleton07 {
private Singleton07(){};
private static class InnerSingleton{
private static Singleton07 INSTANCE = new Singleton07();
}
public static Singleton07 instance(){
return InnerSingleton.INSTANCE;
}
public static void main(String[] args) {
Singleton07 instance = InnerSingleton.INSTANCE;
}
}
8.枚举(最好的方法)
* 优点:
* 我们定义的一个枚举,在第一次被真正用到的时候,会被虚拟机加载并初始化,而这个初始化过程是线程安全的
* 1.代码简洁
* 2.可以防止反射破坏单例模式
* 3.线程安全
/**
* @author: xuxu
* @date 2020/2/2 17:43
* @Description: 枚举(最好的方法)
* 优点:
* 我们定义的一个枚举,在第一次被真正用到的时候,会被虚拟机加载并初始化,而这个初始化过程是线程安全的
* 1.代码简洁
* 2.可以防止反射破坏单例模式
* 3.线程安全
*/
public enum Singleton08 {
//单例实例
INSTANCE;
/**
* 工具类中的方法
*/
public void whateverMethod(){
System.out.println("工具类方法");
}
public static void main(String[] args) {
Singleton08.INSTANCE.whateverMethod();
}
}