單例設(shè)計(jì)模式是最常用的設(shè)計(jì)模式之一.單例模式提供了一種在多線程環(huán)境中保證實(shí)例唯一性的解決方案。
餓漢模式也叫立即加載模式,立即加載就是在使用類時(shí)就已經(jīng)將對(duì)象初始化完畢。
package com.wkcto.sigleton.p1;
/**
* 餓漢單例模式
* 在類加載內(nèi)存時(shí)就給對(duì)象初始化,具有固有的線程安全性
* 餓漢模式適用于成員屬性比較少,占用內(nèi)存資源不多的情況
*/
public class Test {
public static void main(String[] args) {
//創(chuàng)建10個(gè)線程, 在每個(gè) 線程中打印單例對(duì)象
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
//調(diào)用Singleton.getInstance()返回單例對(duì)象,打印會(huì)輸出對(duì)象的哈希碼
System.out.println(Singleton.getInstance());
}
}).start();
}
//程序運(yùn)行后,輸出單例的哈希碼都相同,說明是同一個(gè)對(duì)象
}
}
package com.wkcto.sigleton.p1;
import java.util.Random;
/**
* 單例類
*/
public class Singleton {
//在使用Singleton單例類時(shí),就給靜態(tài)變量obj初始化. 在類加載內(nèi)存時(shí)就已經(jīng)對(duì)類的實(shí)例初始化完畢,保證在多線程環(huán)境中的唯一
private static Singleton obj = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
try {
Thread.sleep(new Random().nextInt(50));
} catch (InterruptedException e) {
e.printStackTrace();
}
return obj;
}
}
懶漢模式也稱為延遲加載. 延遲加載就是在第一次調(diào)用get()方法時(shí)才給實(shí)例進(jìn)行初始化。
package com.wkcto.sigleton.p2;
/**
* 測(cè)試單例模式
*/
public class Test {
public static void main(String[] args) {
//創(chuàng)建10個(gè)線程, 在每個(gè) 線程中打印單例對(duì)象
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
//調(diào)用Singleton.getInstance()返回單例對(duì)象,打印會(huì)輸出對(duì)象的哈希碼
System.out.println(Singleton.getInstance());
}
}).start();
}
}
}
package com.wkcto.sigleton.p2;
import java.util.Random;
/**
* 懶漢單例
* 不是線程安全的
*/
public class Singleton1 {
//定義本類實(shí)例,不初始化
private static Singleton1 obj;
private Singleton1(){}
//在第一次調(diào)用getInstance()方法時(shí),判斷obj是否為null,如果obj為null就進(jìn)行初始化
public static Singleton1 getInstance(){
if ( obj == null ){
try {
Thread.sleep(new Random().nextInt(50)); //睡眠,模擬多線程執(zhí)行需要的時(shí)間,
//加上睡眠后,運(yùn)行結(jié)果可能會(huì)出現(xiàn)多個(gè)實(shí)例的情況,這種延遲加載不是線程安全的
} catch (InterruptedException e) {
e.printStackTrace();
}
obj = new Singleton1();
}
return obj;
}
}
package com.wkcto.sigleton.p2;
import java.util.Random;
/**
* 懶漢單例
* 既然多個(gè) 線程可以同時(shí)調(diào)用getInstance()方法,只需要對(duì)該方法進(jìn)行同步即可
* 對(duì)整個(gè)方法進(jìn)行了同步,并發(fā)效率低,即一個(gè)線程必須等上個(gè)線程釋放鎖之后才能取得 鎖對(duì)象獲得單例
*/
public class Singleton2 {
//定義本類實(shí)例,不初始化
private static Singleton2 obj;
private Singleton2(){}
//在第一次調(diào)用getInstance()方法時(shí),判斷obj是否為null,如果obj為null就進(jìn)行初始化
public static synchronized Singleton2 getInstance(){
if ( obj == null ){
try {
Thread.sleep(new Random().nextInt(50)); //睡眠,模擬多線程執(zhí)行需要的時(shí)間,
} catch (InterruptedException e) {
e.printStackTrace();
}
obj = new Singleton2();
}
return obj;
}
}
package com.wkcto.sigleton.p2;
import java.util.Random;
/**
* 懶漢單例
* 直接同步getInstance()方法,并發(fā)效率低,可以只針對(duì)部分重要代碼進(jìn)行同步
* 即只針對(duì) 給obj對(duì)象初始化的語句進(jìn)行同步,也可能存在線程安全問題
*/
public class Singleton3 {
//定義本類實(shí)例,不初始化
private static Singleton3 obj;
private Singleton3(){}
//在第一次調(diào)用getInstance()方法時(shí),判斷obj是否為null,如果obj為null就進(jìn)行初始化
public static Singleton3 getInstance(){
if ( obj == null ){
try {
Thread.sleep(new Random().nextInt(50)); //睡眠,模擬多線程執(zhí)行需要的時(shí)間,
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Singleton3.class) {
obj = new Singleton3();
}
}
return obj;
}
}
package com.wkcto.sigleton.p2;
import java.util.Random;
/**
* 懶漢單例
* 直接同步getInstance()方法,并發(fā)效率低,可以只針對(duì)部分重要代碼進(jìn)行同步
* 如果只針對(duì) 給obj對(duì)象初始化的語句進(jìn)行同步,也可能存在線程安全問題
* 可以采用雙檢查機(jī)制,在同步代碼塊中再次檢查obj對(duì)象是否為null
*/
public class Singleton {
//定義本類實(shí)例,不初始化
private static Singleton obj;
private Singleton(){}
//在第一次調(diào)用getInstance()方法時(shí),判斷obj是否為null,如果obj為null就進(jìn)行初始化
public static Singleton getInstance(){
if ( obj == null ){
try {
Thread.sleep(new Random().nextInt(50)); //睡眠,模擬多線程執(zhí)行需要的時(shí)間,
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (Singleton.class) {
if (obj == null) { //再次檢查obj是否為null
obj = new Singleton();
}
}
}
return obj;
}
}