01單例模式
用啥方式解決實際問題更合適就用啥方式,我們不追求那些不必要的完美
餓漢模式01 最簡單版但是好用
package xzc._01singleton;
/*
-
餓漢模式01
-
Class.forName() 也行啊
-
1.放單例的靜態變量
-
2.構造方法私有化
-
3.取出單例的靜態化方法
-
- 類加載到內存後就會自動實例化一個單例
-
*/
public class _01hungry {public static final _01hungry INSTANCE = new _01hungry();
private _01hungry() {};
public static _01hungry getInstance(){
return INSTANCE;
}public void sayHello(){
System.out.println(“01hungry”);
}public static void main(String[] args) {
// _01hungry hungry01 = new _01hungry();
// _01hungry hungry02 = new _01hungry();
_01hungry hungry01 = _01hungry.getInstance();
_01hungry hungry02 = _01hungry.getInstance();
System.out.println(hungry01==hungry02);
}
}
餓漢模式02 靜態代碼塊
package xzc._01singleton;
/*
-
餓漢模式02 靜態代碼塊
-
Class.forName() 也行啊 暫時放棄
-
1.放單例的靜態變量
-
2.構造方法私有化
-
3.取出單例的靜態化方法
-
- 類加載到內存後就會自動實例化一個單例
-
不管用到與否 類加載就實例化了
-
*/
public class _02hungry {private static final _02hungry INSTANCE;
/*- 執行順序:
1、類內容(靜態變量、靜態初始化塊) => 實例內容(變量、初始化塊、構造器)
2、父類的(靜態變量、靜態初始化塊)=> 子類的(靜態變量、靜態初始化塊)=> 父類的(變量、初始化塊、構造器)=> 子類的(變量、初始化塊、構造器)
3、(靜態)變量和(靜態)代碼塊的也是有執行順序的,與代碼書寫的順序一致。在(靜態)代碼塊中可以使用(靜態)變量,但是被使用的(靜態)變量必須在(靜態)代碼塊前面聲明。
*
* - */
static {
INSTANCE = new _02hungry();
}
private _02hungry() {};
public static _02hungry getInstance(){
return INSTANCE;
}
public void sayHello(){
System.out.println(“02hungry”);
}public static void main(String[] args) {
// _01hungry hungry01 = new _01hungry();
// _01hungry hungry02 = new _01hungry();
_01hungry hungry01 = _01hungry.getInstance();
_01hungry hungry02 = _01hungry.getInstance();
System.out.println(hungry01==hungry02);
}
} - 執行順序:
懶漢模式01 最簡線程不安全版
順帶複習了線程創建的方式 和lamda 函數
package xzc._01singleton;
/*
** 懶漢模式
-
- 1.定義放單例的靜態變量
-
2.構造方法私有化
-
3.取出單例的靜態化方法
-
解決了自動創建的問題 反而帶來了線程這個更大的的問題
-
*/
public class _03LazySingleton {
private static _03LazySingleton INSTANCE;private _03LazySingleton() {
}public static _03LazySingleton getInstance(){
if (INSTANCE ==null){try { Thread.sleep(10); }catch (InterruptedException e){ e.printStackTrace(); } INSTANCE = new _03LazySingleton(); } return INSTANCE;
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i<50; i++){
// 1 繼承 Thread重寫runable方法
// MyThread myThread = new MyThread();
// myThread.sleep(i);
// myThread.start();
// 2.1實現runnable方法
// Thread myThread = new Thread(new MyThreadRunnable());
// myThread.start();
// 2.2實現runnable方法 匿名內部類 拿來當參數的類,只需要使用一次
// 匿名內部類也就是沒有名字的內部類
// 正因爲沒有名字,所以匿名內部類只能使用一次,它通常用來簡化代碼編寫
// 但使用匿名內部類還有個前提條件:必須繼承一個父類或實現一個接口
// new Thread(new MyThreadRunnable(){
// @Override
// public void run() {
// System.out.println(Thread.currentThread().getName() +“xxxx”+ _03LazySingleton.getInstance().hashCode());
// }
// }).start();
// 2.3實現runnable方法 匿名內部類 加lamda方法
// Lambda 表達式,也可稱爲閉包,它是推動 Java 8 發佈的最重要新特性。
// Lambda 允許把函數作爲一個方法的參數(函數作爲參數傳遞進方法中)。
// 使用 Lambda 表達式可以使代碼變的更加簡潔緊湊
// 這裏只是實現了了一個run方法可以更加簡寫 爲了更加清楚 這裏cv2.2代碼來簡寫
// new Thread(new MyThreadRunnable(){
new Thread(()->{
// @Override
// public void run() {
System.out.println(Thread.currentThread().getName() +"—"+ _03LazySingleton.getInstance().hashCode());
// }
}).start();
}
}
}
///1/
//class MyThread extends Thread {
// @Override
// public void run() {
// System.out.println(Thread.currentThread().getName() +"—"+ _03LazySingleton.getInstance().hashCode());
// }
//}
///2.1/
//class MyThreadRunnable implements Runnable {
// @Override
// public void run() {
// System.out.println(Thread.currentThread().getName() +"—"+ _03LazySingleton.getInstance().hashCode());
// }
//}
懶漢模式02 synchronized 加instance方法版
package xzc._01singleton;
/*
** 懶漢模式 加synchronized版
-
- 1.定義放單例的靜態變量
-
2.構造方法私有化
-
3.取出單例的靜態化方法
-
解決了自動創建的問題 反而帶來了線程這個更大的的問題
-
解決這個問題 加鎖 只有一行 再原來的基礎上多加個 synchronized 去修飾 getInstance方法
-
問題解決了 但是代價是性能降低了
-
*/
public class _04LazySingletonSynchronized {
private static _04LazySingletonSynchronized INSTANCE;private _04LazySingletonSynchronized() {
}public static synchronized _04LazySingletonSynchronized getInstance(){
if (INSTANCE ==null){try { Thread.sleep(10); }catch (InterruptedException e){ e.printStackTrace(); } INSTANCE = new _04LazySingletonSynchronized(); } return INSTANCE;
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i<50; i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName() +"—"+ _04LazySingletonSynchronized.getInstance().hashCode());
}).start();}
}
}
懶漢模式03 synchronized兼顧安全與性能雙重校驗鎖
package xzc._01singleton;
/*
*
-
解決了自動創建的問題 反而帶來了線程這個更大的的問題
-
解決這個問題 加鎖 只有一行 再原來的基礎上多加個 synchronized 去修飾 getInstance方法
-
問題解決了 但是代價是性能降低了
-
性能降低了很大的原因是鎖的範圍太大了 那就減少鎖的範圍吧 把鎖精確放到代碼塊–不夠精確的話···鎖沒用或者耗費更多的性能在鎖上
-
因爲這裏沒用 因爲if判斷和 和鎖裏面的代碼塊沒有一體化
-
做個雙重檢查吧
-
爲啥判斷兩次?
-
第一次要判斷 看起來多了一個判斷的性能消耗 但是要考慮到大多數情況下都是null直接返回,可以省出來上鎖解鎖的消耗 其實是一種優化。
-
第二次判斷保證單例
-
*/
public class _05LazySingletonSynchronized02 {
private static _05LazySingletonSynchronized02 INSTANCE;private _05LazySingletonSynchronized02() {
}public static _05LazySingletonSynchronized02 getInstance(){
// if (INSTANCE ==null){
synchronized(_05LazySingletonSynchronized02.class){
if (INSTANCE ==null){//裏面再重新檢查一遍
try {
Thread.sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}
INSTANCE = new _05LazySingletonSynchronized02();
}
}
// }
return INSTANCE;
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i<50; i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName() +"---"+ _05LazySingletonSynchronized02.getInstance().hashCode());
}).start();
}
}
}
靜態內部類版 (最完美版 比01好)
package xzc._01singleton;
/*
- 利用了classloader的機制來保證初始化instance時只有一個線程,(虛擬機加載classloader只會加載一次)
- 所以也是線程安全的,同時沒有性能損耗,所以一般我傾向於使用這一種。
- 最完美的寫法
- */
public class _06LazyStaticInnerClass{
private _06LazyStaticInnerClass(){}
private static final _06LazyStaticInnerClass INSTANCE=new _06LazyStaticInnerClass();
public static _06LazyStaticInnerClass getInstance(){
return _06LazyStaticInnerClass.INSTANCE;
}
}
終極版 枚舉(java作者推薦)
package xzc._01singleton;
public enum _07SingletonByEnum {
INSTANCE;
public void m(){
System.out.println(“完美中的完美實現單例 不僅解決單例 還解決反序列化”);
}
public static void main(String[] args) {
for (int i = 0; i<50; i++){
new Thread(()->{
System.out.println(Thread.currentThread().getName() +"—"+ _07SingletonByEnum.INSTANCE.hashCode() +"—");
// _07SingletonByEnum.INSTANCE.m();
}).start();
}
}
}