一:单例模式作用:
核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
二:单例模式的优点:
1、由于单例模式只生成一个实例,减少了系统的性能开销,当一个对象的产生需要比较多的
资源时,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例
对象,然后永久驻留内存的方式来解决。
2、单例模式可以在系统设置全局的访问点,优化共享资源访问,例如可以设计一个单例类
负责所有数据表的映射处理。
三:常见的5中单例模式实现方式
主要:
1、饿汉式(线程安全、调用效率高、但是不能延时加载)
2、懒汉式(线程不安全、调用效率不高、但是可以延时加载)
其他:
1、双重检测锁式(由于JVM底层内部模型的原因,偶尔会出问题,不建议使用)
2、静态内部类式(线程安全、调用效率高、可以延时加载)
3、枚举单例(线程安全、调用效率高、但不能延时加载)
不需要延时加载:枚举好于饿汉
需要延时加载:静态内部类好于懒汉
1、饿汉式:
package com.chen.Singleton;
/**
* 饿汉式单例模式
*1、私有化构造器
*2、创建对象
*3、提供静态方法获得实例对象
* 不用加synchronized,饿汉式天生线程安全,但不能延时加载,加载类时就实例化对象
* @author Administrator
*
*/
public class SingletonDemo01 {
// 2、创建对象
private static SingletonDemo01 instance = new SingletonDemo01();
// 1、私有化构造器
private SingletonDemo01() {
}
// 3、提供静态方法获得实例对象
public static SingletonDemo01 getInstance() {
return instance;
}
}
2、懒汉式:
package com.chen.Singleton;
/**
* 懒汉式单例模式,和恶汉式差不多,不同点在于,
* 需要加synchronized来保证单例,可以延时加载
* @author Administrator
*
*/
public class SingletonDemo02 {
private static SingletonDemo02 instance;
private SingletonDemo02() {
}
public static synchronized SingletonDemo02 getInstance() {
if(instance == null) {
instance = new SingletonDemo02();
}
return instance;
}
}
3、静态内部类式:
package com.chen.Singleton;
/**
* 静态内部类实现单例模式
* 兼并了饿汉式和懒汉式的优点,线程安全,效率高,可以延时加载
* @author Administrator
*
*/
public class SingletonDemo03 {
private static class SingletonInstance {
private static final SingletonDemo03 instance = new SingletonDemo03();
}
private SingletonDemo03() {
}
public static SingletonDemo03 getInstance() {
return SingletonInstance.instance;
}
}
4、枚举实现单例模式:
package com.chen.Singleton;
/**
* 枚举实现单例模式
* 唯一缺点:不能延时加载
* 相比其他单例模式:解决了反射、序列化带来的问题
* @author Administrator
*
*/
public enum SingletonDemo04 {
// 枚举类型,本身就是一个单例模式
INSTANCE;
// 添加自己的操作....
public void test() {
System.out.println("你好啊!!!");
}
}
测试:
package com.chen.Singleton;
/**
* 测试单例模式
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) {
test01();
}
public static void test01() {
SingletonDemo01 instance = SingletonDemo01.getInstance();
SingletonDemo01 instance2 = SingletonDemo01.getInstance();
System.out.println(instance);
System.out.println(instance2);
// 枚举类型的调用
SingletonDemo04 instance3 = SingletonDemo04.INSTANCE;
System.out.println(instance3);
instance3.test();
}
}
测试各种单例模式的效率:
package com.chen.Singleton;
import java.util.concurrent.CountDownLatch;
/**
* 测试各种单例模式的效率
* CountDownLatch:同步辅助类
* countDown() 当前线程调用该方法,则计数器减一(建议放在finally中执行)
* await() 调用该方法会一直阻塞线程,直到计数器为0
*
* 测试结果:
* 懒汉式用时比恶汉多大约两个数量级
* @author Administrator
*
*/
public class Test_Effective {
public static void main(String[] args) throws Exception {
long startTime = System.currentTimeMillis();
int threadNum = 10;
// 计数器初始值为10
// 不加final内部类中无法访问
final CountDownLatch count = new CountDownLatch(threadNum);
// 创建10个线程
for(int i = 0; i < threadNum; i++) {
new Thread(new Runnable(){
@Override
public void run() {
for(int i = 0; i < 10000000; i++) {
// 01变为02就可以测试第二种的效率了。
SingletonDemo01 instance = SingletonDemo01.getInstance();
}
// 每个线程执行完成,计数器减一
count.countDown();
}
}).start();
}
// main线程等待,直到计数器为0才开始往下执行
count.await();
long endTime = System.currentTimeMillis();
System.out.println("耗时:"+(endTime - startTime)+"ms");
}
}