单例模式
饿汉式单例模式
public class LazyMan(){
private LazyMan(){}
private final static LazyMan LAZYMAN=new LazyMan();
public LazyMan getInstance(){
return LAZYMAN;
}
}
盲目的没有条件的新建对象,会造成内存的浪费
懒汉式单例模式
public class LazyMan(){
private LazyMan(){}
private final static LazyMan LAZYMAN;
public LazyMan getInstance(){
return new LazyMan();
}
}
但是上面的程序在多线程情况下没有安全性可言,于是有了DSL(双锁单例模式),实际上更像是一个三🔒的模式
/**
* DCL(Double Check Lock)单例模式,简而言之就是双锁问题,用两个锁来让对象实现原子操作。
*/
class SigleTon {
private static boolean flag = true;
private SigleTon () {
synchronized (SigleTon.class) {
if (flag ==true) {
flag = false;
} else {
throw new RuntimeException ("?????");
}
}
System.out.println (Thread.currentThread ().getName () + "\tOK");
}
private volatile static SigleTon singleton;
/**
* 1.分配内存空间
* 2.执行构造方法
* 3.将空间地址复制给变量
* 以上3步执行完成之后,才创建完整的一个实例。
* 因此执行顺序可能会有不同,比如123就是正常,但是由于CPU,jvm具有重排指令的功能,所以可能会导致132,一旦空间分配完成,
* 我们就认为一个对象的实例化完成,那么另一个进程进入的时候就会以为已经完成了对韵对象的获取,那么返回的就是一个空的对象。
* 加上volatile及时的进行可见性的使用,拒绝代码的重排
*/
public static SigleTon getInstance () {
if (singleton == null) {
//只有一个类就可以使用这个代码块,:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着.
//在这里,synchronized 加在这里的话,可以尽可能的减少系统开销,提高速度
synchronized (SigleTon.class) {//第一个锁
if (singleton == null) {//第二个锁,起到判定
singleton = new SigleTon ();
}
return singleton;
}
} else return singleton;
}
}
内部类实现
class Single{
public Single () {
}
public static Single getInstance(){
return inner.SINGLE;
}
private static class inner{
private static Single SINGLE=new Single ();
}
}
但是这个也不是很安全,我们可以利用反射破坏结构;
所以使用枚举来实行单例模式
package JUC.Sigle;
/**
* 枚举类实现单例模式是安全的,无法破坏原子性
*/
public enum EnumSigle {
INSTANCE;
EnumSigle () {
System.out.println (Thread.currentThread ().getName ());
}
public static EnumSigle getInstance(){
return INSTANCE;
}
public void fun(){
System.out.println (this);
}
public static void main (String[] args) {
for (int i = 0; i <1000 ; i++) {
new Thread (()-> EnumSigle.getInstance ()).start ();
}
}
}