实现方式
共三种:
- 饿汉式
- 懒汉式
- 枚举单例
- 静态内部类式 (推荐)
饿汉式
原理:类在初始化加载的时候,会加载内部 静态 成员对象,然后方法被调用的时候,直接返回这个对象
/**
* 测试饿汉式单例模式
* @author 尚学堂高淇 www.sxt.cn
*
*/
public class Demo {
private Demo(){}; //私有化构造器
private static Demo demo = new Demo(); //类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的是线程安全的!
public static Demo getInstance(){ //方法没有同步,调用效率高!
return demo;
}
}
懒汉式
原理:方法被外部调用的时候,先判断对象是否被实例化,如果没有,则实例化返回,如果有 直接返回 该方法需要加同步锁synchronized,
/**
* 测试懒汉式单例模式
*/
public class Demo {
private Demo(){};
private static Demo demo;
public static synchronized Demo getInstance(){ //方法同步,调用效率低!
if(demo == null){
demo = new Demo();
}
return demo;
}
}
枚举单例
优点:
1.实现简单
2.枚举本身就是单例模式。由JVM从根本上提供保障 避免通过反射和反序列化的漏洞
缺点:
1.无延迟加载
/**
* 测试枚举式实现单例模式(没有延时加载)
*/
public enum SingletonDemo5 {
//这个枚举元素,本身就是单例对象!
INSTANCE;
//添加自己需要的操作!
public void singletonOperation(){
}
}
静态内部类式 推荐
1.没有静态 内部 成员对象 所以和饿汉式不一样
2.静态内部类,在调用的时候初始化 懒
3.内部类中成员对象是 static final 保证了在内存中只有一份实例,
/**
* 测试静态内部类实现单例模式
* 这种方式:线程安全,调用效率高,并且实现了延时加载!
* @author 尚学堂高淇 www.sxt.cn
*
*/
public class Demo {
private Demo(){};
//静态内部类
private static class DemoInstance {
private static final Demo instance = new Demo();
}
public static Demo getInstance(){
return DemoInstance.instance;
}
}
比较
主要
- 饿汉式(线程安全,调用效率高,但是 不能延时加载)
- 懒汉式 (线程安全,调用效率不高,但是 可以延时加载) 每次调用getInstance() 方法都要同步,并发效率太低
- 静态内部类式(线程安全,调用效率高。可以延时加载)
- 枚举单例(线程安全,调用效率高,不能延时加载)
测试效率
/**
* 测试多线程环境下五种创建单例模式的效率
*/
public class Client3 {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
int threadNum = 10;
final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
for(int i=0;i<threadNum;i++){
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<1000000;i++){
// Object o = SingletonDemo4.getInstance();
Object o = SingletonDemo5.INSTANCE;
}
countDownLatch.countDown();
}
}).start();
}
countDownLatch.await(); //main线程阻塞,直到计数器变为0,才会继续往下执行!
long end = System.currentTimeMillis();
System.out.println("总耗时:"+(end-start));
}
}