一、單例模式(Singleton) 1、單例模式應用場景: ①Servlet ②任務管理器 ③鏈接池 ④Spring中每個 bean 預設是單例 ⑤網站計數器 2、單例要求 ①構造器私有 ②私有的靜態變數 ③公共的靜態的可以訪問私有的靜態變數的方法 結論:由結果可以得知單例模式為一個面向對象的應用程 ...
一、單例模式(Singleton)
1、單例模式應用場景:
①Servlet
②任務管理器
③鏈接池
④Spring中每個 bean 預設是單例
⑤網站計數器
2、單例要求
①構造器私有
②私有的靜態變數
③公共的靜態的可以訪問私有的靜態變數的方法
結論:由結果可以得知單例模式為一個面向對象的應用程式提供了對象惟一的訪問點,不管它實現何種功能,整個應用程式都會同享一個實例對象。
二、單例模式的實現方式
1、餓漢式
線程安全、立即載入、資源利用率低、調用效率高
package cn.com.zfc.gof01.singleton;
/**
*
* @title Singleton01
* @describe 餓漢式實現單例模式
* @author 張富昌
* @date 2017年3月27日上午8:40:02
*/
public class Singleton01 {
// 天然的線程安全的,類載入是立即載入這個實例
private static Singleton01 instance = new Singleton01();
/ 構造器私有化
private Singleton01() {
}
// 方法沒有同步,效率比較高
public static Singleton01 getInstance() {
return instance;
}
}
2、懶漢式
線程安全、延遲載入、資源利用率高、調用效率低
package cn.com.zfc.gof01.singleton;
/**
*
* @title Singleton02
* @describe 懶漢式實現單例模式
* @author 張富昌
* @date 2017年3月27日上午8:45:42
*/
public class Singleton02 {
private static Singleton02 instance = null;
//構造其私有化
private Singleton02() {
}
//公共,同步,靜態
public static synchronized Singleton02 getInstance() {
if (instance == null) {
instance = new Singleton02();
}
return instance;
}
}
3、雙重檢索式
線程安全、延遲載入、資源利用率高、調用效率高、但不穩定
package cn.com.zfc.gof01.singleton;
/**
*
* @title Singleton03
* @describe 雙重檢測鎖式實現單例模式(不建議使用)
* @author 張富昌
* @date 2017年3月27日上午8:52:59
*/
public class Singleton03 {
private static Singleton03 instance = null;
private Singleton03() {
}
public static Singleton03 getInstance() {
if (instance == null) {
Singleton03 sc;
synchronized (Singleton03.class) {
sc = instance;
if (sc == null) {
synchronized (Singleton03.class) {
if (sc == null) {
sc = new Singleton03();
}
}
instance = sc;
}
}
}
return instance;
}
}
4、靜態內部類式(相比於懶漢式更好)
線程安全、延遲載入、資源利用率高、調用效率高
package cn.com.zfc.gof01.singleton;
/**
*
* @title Singleton04
* @describe 靜態內部類式實現單例模式
* @author 張富昌
* @date 2017年3月27日上午8:54:40
*/
public class Singleton04 {
// 構造器私有化
private Singleton04() {
}
// 靜態內部類
private static class StaticInnerClass {
private static final Singleton04 INSTANCE = new Singleton04();
}
public static Singleton04 getInstance() {
return StaticInnerClass.INSTANCE;
}
}
5、枚舉單例式(相比於餓漢式更好)
線程安全、立即載入、可以天然的防止反射和反序列化
package cn.com.zfc.gof01.singleton;
/**
*
* @title Singleton05
* @describe 枚舉式實現單例模式
* @author 張富昌
* @date 2017年3月27日上午9:01:59
*/
public enum Singleton05 {
// 單例對象
INSTANCE;
// 如果要對該單例對象進行額外的操作,則加入方法
public void singlrtonOperation() {
}
}
三、測試多線程環境下五種創建單例模式的效率
package cn.com.zfc.gof01.singleton.test;
import java.util.concurrent.CountDownLatch;
import cn.com.zfc.gof01.singleton.Singleton05;
/**
*
* @title SingletonTest
* @describe 測試多線程環境下五種創建單例模式的效率
* @author 張富昌
* @date 2017年3月27日上午9:24:58
*/
public class SingletonTest {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
int threadNum = 10;
// A synchronization aid that allows one or more threads to wait until a
// set of operations being performed in other threads completes.
// 計數器(一個線程執行完成就減1)
final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
for (int i = 0; i < threadNum; i++) {
// 多線程測試
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000000; i++) {
// 餓漢式,
// Object o = Singleton01.getInstance();
// 懶漢式,最慢
// Object o = Singleton02.getInstance();
// 雙重檢測鎖式,不穩定,不建議使用
// Object o = Singleton03.getInstance();
// 靜態內部類
// Object o = Singleton04.getInstance();
// 枚舉式
Object o = Singleton05.INSTANCE;
}
// 一個線程執行完成就減1
countDownLatch.countDown();
}
}).start();
}
// 阻塞
countDownLatch.await(); // main線程阻塞,直到計數器變為0,才會繼續往下執行!
long end = System.currentTimeMillis();
System.out.println("總耗時:" + (end - start));
}
}
四、什麼是線程安全?
如果你的代碼所在的進程中有多個線程在同時運行,而這些線程可能會同時運行這段代碼。如果每次運行結果和單線程運行的結果是一樣的,而且其他的變數的值也和預期的是一樣的,就是線程安全的。
或者說:一個類或者程式所提供的介面對於線程來說是原子操作,或者多個線程之間的切換不會導致該介面的執行結果存在二義性,也就是說我們不用考慮同步的問題,那就是線程安全的。