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