1.饿汉式单例模式
/**
* 饿汉式单例模式
* 线程安全的,但是会造成内存浪费,尤其是在没有真正使用到的情况下,性能上也是浪费。
*/
public class SingletonDemo {
private SingletonDemo () {}
private static SingletonDemo singletonDemo = new SingletonDemo();
public static SingletonDemo getInstance() {
return singletonDemo;
}
}
/**
* 饿汉式单例模式
* 利用静态代码块来解决
*/
public class SingletonDemo5 {
private SingletonDemo5() {}
private static SingletonDemo5 singletonDemo = null;
static {
singletonDemo = new SingletonDemo5();
}
public static SingletonDemo5 getInstance() {
return singletonDemo;
}
public static void main(String[] args) {
System.out.println(SingletonDemo5.getInstance());
System.out.println(SingletonDemo5.getInstance());
}
}
2.懒汉式单例
/**
* 懒汉式单例模式
* 线程不安全的,比起饿汉式性能资源上更有优势。
*/
public class SingletonDemo1 {
private SingletonDemo1() {}
private static SingletonDemo1 singletonDemo = null;
public static SingletonDemo1 getInstance() {
/**
* 线程不安全出现在下面的if代码块
* Thread_A 和 Thread_B同时到达if的时候,就会出现两个对象实例。
*/
if(null == singletonDemo){
singletonDemo = new SingletonDemo1();
}
return singletonDemo;
}
}
下面就进行修改,让它成为线程安全的!
变型一:
/**
* 懒汉式单例模式
* 线程安全的,比起饿汉式性能资源上更有优势。
*/
public class SingletonDemo2 {
private SingletonDemo2() {}
private static SingletonDemo2 singletonDemo = null;
/**
* synchronized 只会让一个线程进入创建对象实例。但是
* 会造成性能问题。
* @return
*/
public synchronized static SingletonDemo2 getInstance() {
if(null == singletonDemo){
singletonDemo = new SingletonDemo2();
}
return singletonDemo;
}
}
变型二:
/**
* 懒汉式单例模式
* 线程不安全的,比起饿汉式性能资源上更有优势。
*/
public class SingletonDemo3 {
private SingletonDemo3() {}
private static SingletonDemo3 singletonDemo = null;
/**
* synchronized 下沉到方法内部,这种形式也可以叫做:
* 双重检测同步机制
* 这样同样会有问题:造成的原因是指令重排序
*
* 创建对象简单过程:
* 1.分配对象内存空间
* 2.引用指向刚才分配的内存空间
* 3.初始化对象
*
* 指令重排序会让:2、3进行颠倒
*
*
* @return
*/
public synchronized static SingletonDemo3 getInstance() {
if(null == singletonDemo){ // 线程A 如果是132的过程B->3,A在此处就会直接返回未完成初始化的对象实例
synchronized (SingletonDemo.class) {
if (null == singletonDemo) {
singletonDemo = new SingletonDemo3(); // 线程B - 1【3】2执行到第三步
}
}
}
return singletonDemo;
}
}
针对变型二里面出现的问题,这个时候就要上volatile 这个杀器了,他可以让程序屏蔽指令重排序:
/**
* @author Kevin
*
* 单例设计模式
*
*/
public class SingletonDemo {
private SingletonDemo(){
//不可实例化
}
/**
* volatile保持可见性
*/
private volatile static SingletonDemo singleton;
/**
* @return SingletonDemo
*
* 此方法再指令重排序时候,不能保证安全单例,所以使用volatile。
*
*/
public static SingletonDemo getInstance(){
if(singleton == null){
synchronized (SingletonDemo.class) {
if(singleton == null){
singleton = new SingletonDemo();
}
}
}
return singleton;
}
}
3.利用枚举类的单例写法(推荐)
public class SingletonEnumDemo {
private SingletonEnumDemo() {}
public synchronized static SingletonEnumDemo getInstance() {
return Singleton.INSTANCE.getInstance();
}
private enum Singleton {
INSTANCE;
private SingletonEnumDemo singletonDemo = null;
// JVM保证该方法只会被调用一次,绝对安全
Singleton () {
singletonDemo = new SingletonEnumDemo();
}
public SingletonEnumDemo getInstance () {
return singletonDemo;
}
}
}