单例模式
设计模式之单例模式
饿汉式(静态变量)
class Singleton1{
//1.构造器私有化
private Singleton1() {
}
private static final Singleton1 singleton = new Singleton1();
public static Singleton1 getInstance(){
return singleton;
}
}
优点:安全
缺点:可能造成内存浪费
饿汉式(静态代码块)
class Singleton2{
//构造器私有化
private Singleton2() {
}
private static Singleton2 singleton2;
static{
//在静态代码块中完成初始化
singleton2 = new Singleton2();
}
public static Singleton2 getInstance(){
return singleton2;
}
}
优缺点和上面一样
懒汉式(线程不安全)
/**
* 懒汉式(线程不安全)
*/
public class TestSingleton3 {
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
new Thread(() ->{
System.out.println(Thread.currentThread().getName()+"@@"+Singleton3.getInstance().hashCode());
},String.valueOf(i)).start();
}
}
}
class Singleton3{
//构造器私有
private Singleton3() {
}
private static Singleton3 singleton3;
public static Singleton3 getInstance(){
if(singleton3==null)
singleton3 = new Singleton3();
return singleton3;
}
}
优点:起到了懒加载的效果,但只能在单线程下使用
缺点:多线程下线程不安全
懒汉式(同步方法或同步代码块)
这里只演示同步方法
class Singleton4 {
//构造器私有化
private Singleton4() {
}
private static Singleton4 singleton4;
public static synchronized Singleton4 getInstance() {
if (singleton4 == null)
singleton4 = new Singleton4();
return singleton4;
}
}
优点:多线程下安全
缺点:效率低下
DCL
class Singleton5{
//构造器私有化
private Singleton5() {
}
//注意要加volatile关键字
//volatile关键字在这里的作用主要是保证可见性
private static volatile Singleton5 singleton5;
public static Singleton5 getInstance(){
if (singleton5==null){
synchronized (Singleton5.class){
if(singleton5==null)
singleton5 = new Singleton5();
}
}
return singleton5;
}
}
优点:线程安全,延迟加载,效率较高
在这里说一下volatile的作用
volatile的三大作用:保证可见性,不保证原子性,禁止指令重排
笔者认为volatile在这里的作用主要是保证可见性,当一个线程进入到同步代码块中,它创建完对象后,应立刻对其它线程可见。volatile的
作用就是当被volatile修饰的变量发生变化时,其结果会立刻强制被刷回到主存中,而其它线程会通过总线嗅探机制和缓存一致性协议得知
自己缓存中的数据已经失效,会等待缓存行对应的主存地址被更新之后,再去读取对应的主存中的新值。
当然,这只是笔者认为的,网上的答案也是众说纷坛。笔者的答案只能作为参考,如有不对,请告知于我。
静态内部类
class Singleton6{
//构造器私有化
private Singleton6() {
}
//因为外部类加载的时候不会触发静态内部类的加载
//并且类的静态属性只会在类第一次被加载的时候初始化,
//所以在这里,JVM帮助我们保证了现成的安全性,在类进行初始化时,别的线程是无法进入的。
private static class InnerSingleton{
public static final Singleton6 INSTANCE = new Singleton6();
}
public static Singleton6 getInstance(){
return InnerSingleton.INSTANCE;
}
}
优点:线程安全,延迟加载,效率较高
枚举
enum Singleton7{
INSTANCE;
public void method(){
System.out.println("你好呀!!!");
}
}
优点:线程安全,可以防止反序列化重新创建新的对象,推荐使用。