单例模式(懒汉和饿汉)
Java中指的是单例设计模式 他是软件开发中最常用的设计模式之一。
单:唯一
例:实例
单例设计模式: 在整个系统中,只有一个实例对象可以获得和使用的代码模式
要点:
1.某一类只能有一个例子
构造器私有
2.它必须自己创建这个例子
它含有这种静态变量来保存这个唯一的例子
3.它必须向整个系统提供这个例子
1.直接暴露 2.采用静态变量get法获取
常见的单例形式
饿汉式: (直接创建对象 没有线程安全问题) 1.饿汉式直接实例化 (简单直观)/**
* 饿汉式:
* 实例对象在类初始化时直接创建 无论你是否需要这个对象,你都会创建它
*
*/
public class Singleton {
public static final Singleton INSTANCE=new Singleton();
private Singleton1()
}
2.枚举式 (最简洁)/**
* 饿汉式 枚举类型:表示该类型的对象有限
* 我们可以限制一个,成为单例
*/
public enum Singleton2 {
INSTANCE
}
3.饿汉式静态代码块 (适用于复杂实例化)/**
* 饿汉式 静态代码块 方式
* 适用于 比较复杂 需要一堆初始化数据来创建对象
*/
public class Singleton {
public static final Singleton INSTANCE;
static {
INSTANCE = new Singleton3();
}
private Singleton3() {
}
}
创建实例:
public class Test {
public static void main(String[] args) {
Singleton s = Singleton.INSTANCE;
Singleton2 s2 = Singleton2.INSTANCE;
Singleton s3 = Singleton.INSTANCE;
System.out.println(s);
System.out.println(s2);
System.out.println(s3);
}
}
为什么饿汉风格没有线程安全问题?
因为:
按需加载,只加载一次。因此,当上述单个例类被加载时,将实例化一个对象并交给自己的引用,供系统使用。换句话说,在线程访问单例对象之前就已经创建了。此外,由于一个类只会在整个生命周期中加载一次,单个类只会创建一个例子,也就是说,每次线程只能得到唯一的对象。因此,饿汉单例自然是线程安全的。
懒汉式: (必要时创建对象(延迟创建对象) 存在线程安全问题) 1.线程不安全 (适用于单线程)/**
* 懒汉式 延迟创建对象
* 使用私有结构器
* 用静态变量保存这个唯一的例子
* 提供静态方法 获得这个例子
*/
public class Singleton4 {
private static Singleton4 instance = null;
private Singleton4()
public static Singleton4 getInstance(){
if(instance==null){
instance = new Singleton4();
}
return instance;
}
}
2.线程安全 (适用于多线程)/**
* 第一种
* 懒汉式 延迟创建对象 (线程安全)
*/
public class Singleton5 {
private static Singleton5 instance = null;
private Singleton5()
//在方法上加锁(synchronized) 确保线程安全 这种效率在高并发的情况下相对较低
public synchronized static Singleton5 getInstance(){
if(instance==null){
instance = new Singleton5();
}
return instance;
}
}
/**
* 第二种 DoubleCheck
* 懒汉式 延迟创建对象
*/
public class Singleton6 {
//加上volatile 保证jvm 代码不会重新排序
private static volatile Singleton6 instance = null;
private Singleton6()
//确保线程安全 doublecheck
public static Singleton6 getInstance(){
如果///在线程运行中 instance本身不同于空 那样,就没有必要继续进入锁 (效率高于直接锁定给方法)
if(instance==null){
synchronized (Singleton6.class){
if(instance==null){
instance = new Singleton6();
}
}
}
return instance;
}
}
3.静态内部类形式 (适用于多线程)/**
* 当内部类被加载和初始文字时, 创建INSTANCE实例对象
* 静态内部类不会随着外部类的加载和初始化而自动初始化。它需要单独加载和初始化
* 因为它是在内部加载和初始单词中创建的 所以线程是安全的
*/
public class Singleton7 {
private Singleton7()
private static class inner{
private static final Singleton7 INSTANCE=new Singleton7();
}
public static Singleton7 getInstance(){
return inner.INSTANCE;
}
}