引言
平时经常使用别人写好的框架,但是没有过多的深究,之前写过相关的博文,只是缺少代码解释,所以在这里进行补充,并且做个复习。
什么是单例
所谓的单例,也就是单一实例,再进一步说,也就是再内存中只有一个对象。想到一个罗曼蒂克的词语,理科生应该能够体会得到内涵,有且仅有。🤭。
类别
懒汉式:也就是说真正用到的时候才会创建实例。
饿汉式:在一开始的时候就创建这个实例。
双重检查锁:个人认为是懒汉式的优化版。
代码实现
懒汉式
Lazy.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
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());
}
}
运行结果
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
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());
}
}
运行结果
Thread-1<-->HUNGER<-->1030697658
Thread-2<-->HUNGER<-->1030697658
Thread-0<-->HUNGER<-->1030697658
双重检查锁
LockTest
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提供了内存的可见性, 每个线程对器进行操作后,其他线程都会感知到, 并且从主存中获取这个变量,而不是缓冲区, 保证了实时性.

评论 0
还没有评论,来说点什么吧。