Loading... # 引言 平时经常使用别人写好的框架,但是没有过多的深究,之前写过相关的博文,只是缺少代码解释,所以在这里进行补充,并且做个复习。 # 什么是单例 所谓的单例,也就是单一实例,再进一步说,也就是再内存中只有一个对象。想到一个罗曼蒂克的词语,理科生应该能够体会得到内涵,有且仅有。🤭。 # 类别 懒汉式:也就是说真正用到的时候才会创建实例。 饿汉式:在一开始的时候就创建这个实例。 双重检查锁:个人认为是懒汉式的优化版。 # 代码实现 ## 懒汉式 Lazy.java ```java package top.zunmx.demo; public class Lazy { public static Lazy obj; // 静态变量 private Lazy(){} // 私有构造方法 public synchronized static Lazy getInstance(){ if(obj==null){ obj = new Lazy(); System.out.println("LAZE-CREATED BY "+Thread.currentThread().getName()); } return obj; } public String func(){ return "LAZY"; } } ``` LTest.java ```java package top.zunmx.demo; public class LTest extends Thread { public static void main(String[] args) { LTest t1 = new LTest(); t1.start(); LTest t2 = new LTest(); t2.start(); LTest t3 = new LTest(); t3.start(); } @Override public void run() { System.out.println(Thread.currentThread().getName() + "<-->" + Lazy.getInstance().func() + "<-->" + Lazy.getInstance().hashCode()); } } ``` 运行结果 ```bash LAZE-CREATED BY Thread-1 Thread-1<-->LAZY<-->1700405589 Thread-0<-->LAZY<-->1700405589 Thread-2<-->LAZY<-->1700405589 ``` ## 饿汉式 Hunger.java ``` package top.zunmx.demo; public class Hunger { private static Hunger hunger = new Hunger(); private Hunger (){} public static Hunger getInstance(){ return hunger; } public String func(){ return "HUNGER"; } } ``` HTest.java ```java package top.zunmx.demo; public class HTest extends Thread { public static void main(String[] args) { HTest t1 = new HTest(); t1.start(); HTest t2 = new HTest(); t2.start(); HTest t3 = new HTest(); t3.start(); } @Override public void run() { System.out.println(Thread.currentThread().getName() + "<-->" + Hunger.getInstance().func() + "<-->" + Hunger.getInstance().hashCode()); } } ``` 运行结果 ```bash Thread-1<-->HUNGER<-->1030697658 Thread-2<-->HUNGER<-->1030697658 Thread-0<-->HUNGER<-->1030697658 ``` ## 双重检查锁 LockTest ```java package top.zunmx.demo; public class LockTest extends Thread { private LockTest() { } private volatile static LockTest lockTest = null; public static LockTest getInstance() { if (lockTest == null) { synchronized (LockTest.class) { if (lockTest == null) { lockTest = new LockTest(); System.out.println("CREATE OBJECT BY " + Thread.currentThread().getName()); } } } return lockTest; } public String func(){ return "LOCK"; } @Override public void run() { System.out.println(Thread.currentThread().getName() + "<-->" + LockTest.getInstance().func() + "<-->" + LockTest.getInstance().hashCode()); } public static void main(String[] args) { LockTest t1 = new LockTest(); LockTest t2 = new LockTest(); LockTest t3 = new LockTest(); t1.start(); t2.start(); t3.start(); } } ``` # 结论 懒汉式: 懒汉式只有在调用的时候才会创建, 当创建实例时,为了保证线程的安全,需要在获取实例的时候加锁,然而每次获取实例对象都需要加锁和解锁,对象创建一次就好,一般情况取对象时上锁显得多此一举,上锁和解锁是需要耗费资源和时间的,所以这种形式不是很优雅. 饿汉式: 当加载类的时候就创建对象,一劳永逸,虽然看起来没有什么问题,但是如果这个类加载多次,会导致创建多次实例,这样也会造成性能的浪费. 双重检查锁: 这里涉及到了volatile关键字, 如果了解汇编语言,就会知道,在我们的代码中的一行, 对应的机器语言可能是多条指令, 这些指令由编译器进行优化的时候,可能会进行删减和排序, volatile可以禁止指令重新排序, 所以也就是说, 在对于volatile修饰的变量进行操作的时候是根据代码的顺序进行执行. 并且volatile提供了内存的可见性, 每个线程对器进行操作后,其他线程都会感知到, 并且从主存中获取这个变量,而不是缓冲区, 保证了实时性. © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏