单例模式---双重检测锁实现

饿汉模式:
饿汉式(线程安全,调用效率高。 但是,不能延时加载。)
属于类线程安全,所以不需要关键字 :
synchonrized

/**
 *  饿汉式
 * @author Administrator
 *
 */
public class SignOne {
    
    
	
	private static SignOne instance = new SignOne();
	
	public static /*synchronized*/ SignOne newInstance()
	{
    
    
		return instance;
	}

}

懒汉式: 懒汉式(线程安全,调用效率不高。 但是,可以延时加载。)资源利用率高了。但是,每次调用getInstance()方法都要同步,并发效率较低。
public class SignOne {
    
    
	private static SignOne instance;
	public static synchronized SignOne newInstance()
	{
    
    
		if ( instance == null)
		{
    
    
			instance = new SignOne();
		}
		return instance;
	}
}

  • 单例 (Singleton)
    synchronized 关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了。
public static Singleton getInstance() {
    
    
	if (instance == null) {
    
    
		 synchronized (instance) {
    
    
			if (instance == null) 
			{
    
    
				instance = new Singleton();
			}
		}
	}
	 return instance;
}

将 synchronized 关键字加在了内部,也就是说当调用的时候是不需要加
锁的,只有在 instance 为 null,并创建对象的时候才需要加锁,性能有一定的提升。但是,这样的情况,还是有可能有问题的,看下面的情况:在 Java 指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的。但是 JVM 并不保证这两个操作的先后顺序,也就是说有可能 JVM 会为新的 Singleton 实例分配空间,然后直接赋值给 instance 成员,然后再去初始化这个 Singleton 实例。这样就可能出错了,我们以 A、B 两个线程为例:
a>A、B 线程同时进入了第一个 if 判断
b>A 首先进入 synchronized 块,由于 instance 为 null,所以它执行 instance = new Singleton();
c>由于 JVM 内部的优化机制,JVM 先画出了一些分配给 Singleton 实例的空白内存,并赋值给 instance
成员(注意此时 JVM 没有开始初始化这个实例),然后 A 离开了 synchronized 块。
d>B 进入 synchronized 块,由于 instance 此时不是 null,因此它马上离开了 synchronized 块并将结果
返回给调用该方法的程序。
e>此时 B 线程打算使用 Singleton 实例,却发现它没有被初始化,于是错误发生了。


双重锁机制:
这个模式将同步内容下方到if内部,提高了执行的效率不必每次获取对象时都进行同步,只有第一次才同步创建了以后就没必要了。
由于编译器优化原因和JVM底层内部模型原因,偶尔会出问题。不建议使用

public class SignLetonDoubleLock {
    
    

	private static SignLetonDoubleLock signLetonDoubleLock;

	private SignLetonDoubleLock() {
    
    
	}

	public static SignLetonDoubleLock newInstance() {
    
    
		if (signLetonDoubleLock == null) {
    
    
			SignLetonDoubleLock sc;
			synchronized (SignLetonDoubleLock.class) {
    
    
				sc = signLetonDoubleLock;
				if (sc == null)
				{
    
    
					synchronized (SignLetonDoubleLock.class)
					{
    
    
						if ( sc == null )
						{
    
    
							sc = new SignLetonDoubleLock();
						}
					}
				}
				signLetonDoubleLock = sc;
			}
		}
		return signLetonDoubleLock;
	}
}

静态内部类实现方式(也是一种懒加载方式)
外部类没有static属性,则不会像饿汉式那样立即加载对象。
只有真正调用getInstance(),才会加载静态内部类。加载类时是线程 安全的。 instance是static final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性.
兼备了并发高效调用和延迟加载的优势!

public class SignTwo {
    
    
	
	private SignTwo() {
    
    }
	
	public static SignTwo newInstance()
	{
    
    
		return SingletonClassInstance.S_TWO;
	}
	
	private static class SingletonClassInstance
	{
    
    
		private static final SignTwo S_TWO = new SignTwo();
	}

}

在这里插入图片描述
CountDownLatch
同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
countDown() 当前线程调此方法,则计数减一(建议放在 finally里执行)
await(), 调用此方法会一直阻塞当前线程,直到计时器的值为0

猜你喜欢

转载自blog.csdn.net/qq_16183731/article/details/94765249