运用场景
在学习单例设计形式前,我想应该先去了解这种形式是在什么样的布景下发生的,这有利于后续学习时的了解。记住我自己最早真正运用到单例形式,是在进行数据库衔接的时分,当时在做原生项目的时分,由于需求常常拜访数据库,就会常常打开和封闭数据库衔接,这种办法会导致项目的功率下降。在这种场景下,假如运用一个类,来对数据库资源的衔接进行封装,确保在整个项目中,只要一个该类供给的目标,就能够避免上述的问题。所以,单例形式的效果也就体现出来了,当然它的运用场景还有许多,例如项目日志输出,计算网站在线人数等。
A8站源码交易平台
界说
单例形式开始的界说呈现于《设计形式》(艾迪生维斯理,1994):“确保一个类仅有一个实例,并供给一个拜访它的全局拜访点。”在Java中单例形式的界说是:“一个类有且仅有一个实例,并且自行实例化向整个体系供给。”
A8站源码交易平台
完成思路
单例形式分为饿汉式和懒汉式两种,两者完成的思路相同:
1.在单例类中,供给一个私有静态特色,用于接收实例化目标;
2.在单例类中,构造办法有必要私有化,避免在类外进行实例化;
3.在单例类中,向类外供给一个获取类目标的公有静态办法。
代码完成
饿汉式单例形式完成
饿汉式单例形式:在体系加载类的时分就会创立类的目标,并保存在类中。它的特色是线程安全,以空间换时刻。
public class Singleton {
//1、私有静态特色
private static Singleton instance = new Singleton();
//2、私有构造办法
private Singleton() {
System.out.println("***创立Singleton类目标***");
}
//3、公有静态办法
public static Singleton getInstance() {
return instance;
}
//测验
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
//程序履行成果
***创立Singleton类目标***
true
懒汉式单例形式完成
懒汉式单例形式:在体系加载类的时分不创立类的目标,直到第一次运用类的目标时才会进行创立。它的特色是线程不安全,以时刻换空间。
A8站源码交易平台
public class Singleton {
//1、私有静态特色
private static Singleton instance = null;
//2、私有构造办法
private Singleton() {
System.out.println("***创立Singleton类目标***");
}
//3、公有静态办法
public static Singleton getInstance() {
//判别类目标是否为空,若为空则创立类目标
if(instance == null){
instance = new Singleton();
}
return instance;
}
//测验
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
//程序履行成果
***创立Singleton类目标***
true
懒汉式单例形式是存在线程风险的,下面咱们来测验一下,是不是像说的那样真的存在线程风险?
public class Singleton {
//1、私有静态特色
private static Singleton instance = null;
//2、私有构造办法
private Singleton() {
System.out.println("【" + Thread.currentThread().getName() + "】***创立Singleton类目标***");
}
//3、公有静态办法
public static Singleton getInstance() {
//判别类目标是否为空,若为空则创立类目标
if(instance == null){
instance = new Singleton();
}
return instance;
}
public void print() {
System.out.println("**履行print()办法**");
}
//测验
public static void main(String[] args) {
//创立三个线程目标并运转
for(int i = 0; i < 3; i++){
new Thread(() -> {
//在线程运转过程中,获取Singleton类目标
Singleton.getInstance().print();
}, "线程目标 - " + i).start();
}
}
}
//程序履行成果
【线程目标 - 0】***创立Singleton类目标***
【线程目标 - 1】***创立Singleton类目标***
**履行print()办法**
【线程目标 - 2】***创立Singleton类目标***
**履行print()办法**
**履行print()办法**
经过程序的履行成果,发现当有了若干个线程目标,当前的程序就能够发生多个Singleton类的目标。明显,这不符合单例形式的特色,由于单例形式要求在程序的全体运转中只发生一个实例化目标。造成上述问题的关键是,代码自身呈现了不同步的情况,而处理的中心就在于进行同步处理。
A8站源码交易平台
懒汉式单例形式改善
完成代码同步,咱们需求运用到sychronized关键字。改善办法一,直接对公有静态办法做同步处理:
public static synchronized Singleton getInstance() {
//判别类目标是否为空,若为空则创立类目标
if(instance == null){
instance = new Singleton();
}
return instance;
}
//程序履行成果
【线程目标 - 0】***创立Singleton类目标***
**履行print()办法**
**履行print()办法**
**履行print()办法**
按照上述办法,咱们的确完成了单例形式的要求,确保在程序全体运转过程中,单例类只供给一个实例化的目标。可是,运用这种办法做同步处理,功率会比较低,由于在整个办法中只要一个当地需求做同步处理,下面咱们运用同步代码块进行更合理的同步处理。
A8站源码交易平台
public static Singleton getInstance() {
//判别类目标是否为空,若为空则创立类目标
if(instance == null){
//同步代码块,静态办法中不允许运用this关键字,这里运用类的Class目标
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
//程序履行成果
【线程目标 - 0】***创立Singleton类目标***
**履行print()办法**
**履行print()办法**
**履行print()办法**
经过对“判别instance目标是否为空”作同步处理,这种办法能够减小同步发生的代价,使程序的履行功率更高一些。
懒汉式单例形式完成,运用这种办法也被称为DCL(两层检查加锁)。另外,为了在程序性能上再做一点提升,能够在单例形式的特色声明上运用volatile关键字,
A8站源码交易平台例如:
