1.饿汉式,类加载的时候就创建一个对象(静态成员变量在类加载的时候初始化),不会带来线程安全问题,可能会带来效率问题
package singleton;
/**
* @author Administrator 饿汉式 类加载的时候就创建一个单例对象,不会带来线程安全问题,可能会带来效率问题
*/
public class EagerSingleton {
private static EagerSingleton singleInstance = new EagerSingleton();
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return singleInstance;
}
}
2.懒汉式,只有当单例类用到的时候才会创建对象,非线程安全(多线程切换)
package singleton;
/**
*
* @author Administrator 懒汉式 只有当单例类用到的时候才会创建对象,非线程安全(多线程切换)
*/
public class LazySingleton {
private static LazySingleton singleInstance = null;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (null == singleInstance) {
singleInstance = new LazySingleton();
}
return singleInstance;
}
}
2.1 懒汉式变种一,为了解决线程安全的问题,给获取实例的对象的方法加关键字synchronized同步(缺点:每次都要同步,影响性能)
package singleton;
public class LazySynchronizedSingleton {
private static LazySynchronizedSingleton singletonInstance = null;
private LazySynchronizedSingleton() {
}
public synchronized static LazySynchronizedSingleton getInstance() {
if (null == singletonInstance) {
singletonInstance = new LazySynchronizedSingleton();
}
return singletonInstance;
}
}
2.2 懒汉式变种二,双检锁(既解决了线程安全问题,同时没有性能影响)
package singleton;
/**
*
* @author Administrator
* 双检锁
*/
public class DoubleCheckLockSingleton {
private static DoubleCheckLockSingleton singleInstance = null;
private DoubleCheckLockSingleton() {
}
public static DoubleCheckLockSingleton getInstance() {
if (null == singleInstance) {
synchronized (DoubleCheckLockSingleton.class) {
if (null == singleInstance) {
singleInstance = new DoubleCheckLockSingleton();
}
}
}
return singleInstance;
}
}
2.3 懒汉式之变种三,静态内部类(效果同上)
package singleton;
/**
*
* @author Administrator
* 静态内部类
*/
public class StaticInnerClassSingleton {
private static class LazyHolder {
private static final StaticInnerClassSingleton instance = new StaticInnerClassSingleton();
}
private StaticInnerClassSingleton() {
}
public static StaticInnerClassSingleton getInstance() {
return LazyHolder.instance;
}
}
2017-11-30 11:41更新
这里更新主要是为了解释下双检锁的两次判断对象是否为NULL,
第一次判断为NULL是为了提高效率,因为在实际项目中大多数情况下不会用到并发,所以不需要在每一次获取实例对象时
都要加锁,这样会导致效率降低,否则双检锁和在方法上加synchronized关键字的做法也没什么区别了。
第二次判断为NULL是为了防止出现两个实例对象,这样会失去了单例的意义,想象下这种场景,在极高并发场景下,两个线程都进入第一个if判断,一个
线程拿到了锁,另一个没有拿到,阻塞在外面,拿到锁的线程实例化了一个对象,然后释放锁,然而等待的线程并不知道已经有一个实例被初始化了,因此
有实例化一个对象,这就违反了单例的原则, 因此,需要在锁中再判断是否有对象已被实例化。
~end