http://c.biancheng.net/view/1338.html
https://www.cnblogs.com/zhucj-java/p/13534551.html
https://www.cnblogs.com/restartyang/articles/7770856.html
https://www.imooc.com/article/310708
單例模式定義
單例模式是指一個類只有一個實(shí)例,而且該類可以自己創(chuàng)建自己的實(shí)例啄踊。
單例模式的應(yīng)用
1.在高并發(fā)的系統(tǒng)中生成單號要求唯一袁串,可以將生成單號的實(shí)例寫為單例模式
2.數(shù)據(jù)庫中的連接池
3.枚舉類
4.系統(tǒng)中的上下文
5.spring中@Autowired默認(rèn)注入的是單例注入
6.spring中在需要@Autowired默認(rèn)注入的是多例注入時可在需要注入的類加上@Scope(value="prototype")---prototype原型模式,每次獲取Bean的時候會有一個新的實(shí)例
單例模式的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
1.由于在系統(tǒng)內(nèi)存中只存在一個對象蚊逢,因此可以 節(jié)約系統(tǒng)資源,當(dāng) 需要頻繁創(chuàng)建和銷毀的對象時單例模式無疑可以提高系統(tǒng)的性能。
2.單例模式設(shè)置全局訪問點(diǎn)庭砍,可以優(yōu)化和共享資源的訪問性置。
3.避免對共享資源的多重占用拾并。
缺點(diǎn)
1.單例模式?jīng)]有接口,擴(kuò)展困難鹏浅,則除了修改原來的代碼嗅义,沒有第二種途徑,違背開閉原則隐砸。
單例模式的實(shí)現(xiàn)
分為餓漢式和懶漢式之碗、其中餓漢式在類被加載時就創(chuàng)建了實(shí)例、懶漢式在第一次調(diào)用時創(chuàng)建實(shí)例(在多線程下有線程安全問題)
餓漢式實(shí)現(xiàn)
/**
* 單例模式-餓漢式
* 餓漢式不管有沒有調(diào)用getInstance()方法,都會預(yù)先在系統(tǒng)中創(chuàng)建一個靜態(tài)對象
* 餓漢式優(yōu)點(diǎn): 在多線程模式下是安全的
* 缺點(diǎn): 沒有調(diào)用方法前就被加載季希,會占用內(nèi)存
*/
public class BaJie extends JPanel {
private static volatile BaJie instance = new BaJie();
private BaJie(){
JLabel j = new JLabel(new ImageIcon("src/main/resources/img/Bajie.jpg"));
this.add(j);
}
public static BaJie getInstance(){
return instance;
}
public static void main(String[] args) {
JFrame jf = new JFrame("餓漢式單例模式測試");
jf.setLayout(new GridLayout(1, 2));
Container contentPane = jf.getContentPane();
BaJie baJie = BaJie.getInstance();
contentPane.add(baJie);
BaJie baJie2 = BaJie.getInstance();
contentPane.add(baJie2);
if(baJie == baJie2){
System.out.println("他們是同一個人");
} else {
System.out.println("他們不是同一個人");
}
jf.pack();
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
運(yùn)行結(jié)果:
他們是同一個人
懶漢式實(shí)現(xiàn)
為解決在多線程下不安全對創(chuàng)建實(shí)例的方法加鎖synchronized
/**
* 單例模式--懶漢式
* 該模式的特點(diǎn)是類加載時沒有生成單例褪那,只有當(dāng)?shù)谝淮握{(diào)用 getlnstance 方法時才去創(chuàng)建這個單例
* 懶漢式優(yōu)點(diǎn):只有調(diào)用方法才創(chuàng)建對象,不會占用內(nèi)存
* 缺點(diǎn):在多線程模式下不安全
*/
public class President {
private static volatile President instance = null;
//private 避免類在外部被實(shí)例化
private President(){
System.out.println("生產(chǎn)一個美國總統(tǒng)");
}
/**
* synchronized為解決多線程下懶漢式存在的線程安全問題
* synchronized 給對象和方法或代碼塊加鎖式塌,使得同一時刻只有一個線程執(zhí)行該代碼
* @return
*/
public static synchronized President getInstance(){
if (instance == null){
instance = new President();
} else {
System.out.println("已有美國總統(tǒng)博敬,不能再生產(chǎn)!");
}
return instance;
}
public void getName(){
System.out.println("獲得一個美國總統(tǒng):特朗普");
}
public static void main(String[] args) {
//線程1
Thread thread1 = new Thread(){
@Override
public void run(){
President d1 = President.getInstance();
System.out.println(d1.hashCode());
}
};
thread1.start();
//線程2
Thread thread2 = new Thread(){
@Override
public void run(){
President d2 = President.getInstance();
System.out.println(d2.hashCode());
}
};
thread2.start();
President d3 = President.getInstance();
System.out.println(d3.hashCode());
}
}
main執(zhí)行結(jié)果:
生產(chǎn)一個美國總統(tǒng)
338093198
已有美國總統(tǒng)峰尝,不能再生產(chǎn)偏窝!
338093198
已有美國總統(tǒng),不能再生產(chǎn)武学!
338093198
在多線程下通過加鎖可以解決線程安全問題
如果不加synchronized執(zhí)行結(jié)果為:
生產(chǎn)一個美國總統(tǒng)
生產(chǎn)一個美國總統(tǒng)
1587888397
已有美國總統(tǒng)祭往,不能再生產(chǎn)!
1368198263
1587888397
產(chǎn)生了1587888397火窒、1368198263兩個實(shí)例
擴(kuò)展為有限的多例模式Multitcm
生成指定個數(shù)的實(shí)例存到Map中硼补,使用時隨機(jī)取一個使用
有限的多例模式實(shí)現(xiàn)
/**
* 多例模式Multitcm
* 維護(hù)一個指定數(shù)量的對象池,當(dāng)請求個數(shù)超過控制的總數(shù)時熏矿,開始循環(huán)重復(fù)使用
*/
public class DuoLi {
private static int num = 4; //對象數(shù)量
private static int count = 1; //對象序號
private static Map<Integer, DuoLi> map = new HashMap();
static {
for (int i=1; i<=num; i++){
map.put(i, new DuoLi());
}
}
private DuoLi(){
}
public static DuoLi getInstance(){
DuoLi duoLi = map.get(count);
System.out.println(String.format("我是第%s個實(shí)例", count));
count++;
if (count > num){
count = 1;
}
return duoLi;
}
public static void main(String[] args) {
for (int i=0; i<5; i++){
DuoLi duoLi = DuoLi.getInstance();
System.out.println(duoLi.hashCode());
}
}
}
執(zhí)行結(jié)果為
我是第1個實(shí)例
1558600329
我是第2個實(shí)例
636718812
我是第3個實(shí)例
445051633
我是第4個實(shí)例
1051754451
我是第1個實(shí)例
1558600329
第五次取的對象為第一個實(shí)例
剩下的問題
已知類的創(chuàng)建方式有 new括勺,反射、序列化曲掰、克隆
在單例模式由于構(gòu)建方法被私有化不可通過new創(chuàng)建疾捍,那么反射、序列化栏妖、克隆是否可以創(chuàng)建第二個實(shí)例呢乱豆?
https://my.oschina.net/u/3568600/blog/1827375