单例模式(Singleton)
保证一个类的实例在特定范围只有一份(例如一个JVM内部,一个线程内部),并且提供全局访问点可以访问到这份实例。
应用场景
- Spring(Singleton作用域的Bean对象,Spring只是把对象存放于map容器,并提供了一个访问点)
- Mybatis(ErrorContext对象是每个线程一份此类实例)
- Class对象
- 常量池。。。(线程池、连接池都可以设计为单例)
对象分析
- 具体产品对象(例如Singleton)
应用分析
- 优势:科学使用资源,避免频繁创建、销毁对象时造成的资源浪费
- 劣势:设计不够严谨会存在线程安全问题,可扩展性相对较差
举个栗子
class Singleton01 {//此设计在多线程环境中存在不安全
private Singleton01(){}
private static Singleton01 instance;
public static Singleton01 getInstance() {
if (instance == null) {
instance = new Singleton01();
}
return instance;
}
}
class Singleton02 {
private Singleton02(){}
private static Singleton02 instance;
//场景:大对象,稀少用,频繁访问会导致大量阻塞
public static synchronized Singleton02 getInstance() {
if (instance == null) {
instance = new Singleton02();
}//对象创建:延迟创建,按需加载,延迟加载
return instance;
}
}
class Singleton03 {//特点同Singleton02,jdk8之前同步代码块比同步方法性能好一些
private Singleton03(){}
private static Singleton03 instance;
public static Singleton03 getInstance() {
synchronized(Singleton03.class) {
if (instance == null) {
instance = new Singleton03();
}
}
return instance;
}
}
class Singleton04 {
private Singleton04(){}
/**
* 当有一个变量是多线程共享访问时,而且我们要保证变量的安全性,尽量使用volatile修饰
* 双重检查机制通常会用到volatile
* volatile:JMM(需要了解JMM)
*
* 1)保证可见性(一个线程修改结束,其他线程可见)
* 2)禁止指令重排序
* 3)但是不能保证原子性,所以一般用于修饰变量
*
* instance=new Singleton();
* a)堆内存开辟空间
* b)对象属性初始化
* c)执行构造方法
* d)为变量instance赋值
* JVM可能会优化执行过程,导致指令重排序:比如b、d可能会颠倒顺序
*/
private static volatile Singleton04 instance;
/**
* 基于Singleton03进行优化
* 1)尽量减少阻塞的线程
* 2)尽量缩小锁的应用范围(锁的代码块)
*/
public static Singleton04 getInstance() {
if(instance == null) {//双重验证。
synchronized (Singleton04.class) {
if (instance == null) {
instance = new Singleton04();
}
}
}//大对象,稀少用
return instance;
}
}
class Singleton05 {
//private int[] array=new int[4096*1024];
/**
* 类加载时创建(实时加载)
*/
private static Singleton05 instance=
new Singleton05();
private Singleton05(){}
//适合小对象,频繁访问
//大对象容易内存溢出
public static Singleton05 getInstance() {
return instance;
}
//Singleton05.show();
//public static void show(){}
}
class Singleton06 {
//private int[] array=new int[4096*1024];
/**
* 基于内部类实现对象的延迟加载策略
*/
static class Inner {
private static Singleton06 instance =
new Singleton06();
}
private Singleton06(){}
//适合大对象,频繁访问
public static Singleton06 getInstance() {
return Inner.instance;
}
//Singleton05.show();
//public static void show(){}
}
/**
* 枚举类型:基于枚举类型创建单例对象
*/
enum Singleton07{//Singleton07.class
instance;//此实例在类加载时创建
//Singleton07.instance输出instance名字,因为调用了toString方法
private Singleton07(){}
}
public class Demo {
public static void main(String[] args) {
// System.out.println(Singleton01.getInstance());
// System.out.println(Singleton01.getInstance());
// System.out.println(Singleton01.getInstance());
List<Thread> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(new Thread() {
@Override
public void run() {
System.out.println(Singleton01.getInstance());
}
});
}
for (Thread thread : list) {
thread.start();
}
}
}