日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

多线程安全单例模式

發布時間:2023/12/10 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多线程安全单例模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是單例模式?

??在文章開始之前我們還是有必要介紹一下什么是單例模式。單例模式是為確保一個類只有一個實例,并為整個系統提供一個全局訪問點的一種模式方法。

從概念中體現出了單例的一些特點:

(1)、在任何情況下,單例類永遠只有一個實例存在
(2)、單例需要有能力為整個系統提供這一唯一實例

1. 全局變量的缺點:

??必須在程序一開始就創建好對象,如果程序在這次的執行過程中又一直沒用到它,就非常耗費資源。

2. 經典的單例模式實現:

public class Singleton { //用一個靜態變量來記錄Singleton類的唯一實例 //1、提供私有的屬性 --> 存儲對象的地址 private static Singleton uniqueInstance;//2、私有地構造方法 --> 只能本類可以創建對象private Singleton() {} //注意這個方法也是靜態的 -->獲取屬性 public static Singleton getInstance() { if(uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } }

單例常被用來管理共享的資源,例如 數據庫連接、線程池、緩存、注冊表, Spring中大量用到單例模式。
單例模式確保一個類只有一個實例,并提供一個全局訪問點。
這個模式的問題:在多線程時,并不能保證這個類只被實例化一次。

3. 處理多線程:

public class Singleton { //用一個靜態變量來記錄Singleton類的唯一實例 private static Singleton uniqueInstance; private Singleton() {} //注意這個方法也是靜態的 使用synchronized線程同步 public static synchronized Singleton getInstance() { if(uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } }

??通過增加synchronized關鍵字到**getInstance()**方法中,迫使每個線程在進入方法之前,要先等別的線程離開該方法。也就是說,不會有兩個線程可以同時進入這個方法。

這種方法存在的問題:只有第一次執行此方法時,才真正需要同步。換句話說,一旦設置好uniqueInstance變量,就不再需要同步這個方法了。之后每次調用這個方法,同步都是一種浪費。

4.改善多線程

4.1 如果getInstance()的性能對應用程序不是很關鍵,就不用優化了
4.2 使用急切創建實例,而不用延遲實例化的做法
public class Singleton {//實例化時就創建對象 單例模式中的餓漢式private static Singleton uniqueInstance = new Singleton();private Singleton() {}public static Singleton getInstance() { return uniqueInstance; } }

?? private static Singleton uniqueInstance = new Singleton();在靜態初始化器(static initializer)中創建單例,這保證了線程安全。
??利用這個做法,JVM在加載這個類時馬上創建此唯一的單件實例。JVM保證任何線程訪問uniqueInstance靜態變量之前,一定先創建些實例。

4.3 用“雙重檢查加鎖”,在getInstance()中減少使用同步

??首先檢查實例是否已經創建,如果尚未創建,才進行同步。這樣一來,只有第一次會同步,這正是我們想要的。

public class Singleton {//volatile其他線程可能訪問一個沒有初始化的對象private volatile static Singleton uniqueInstance;private Singleton() {}public static Singleton getInstance() { if(uniqueInstance == null) { //(1)//只有第一次才徹底執行這里的代碼 synchronized() { //再檢查一次 if(uniqueInstance == null) uniqueInstance = new Singleton(); } } return uniqueInstance; } }

??在最開始如果有1、2、3個線程走到了(1)處,假設1進入了同步塊,2、3等待。1實例化后,2進入同步塊,發現uniqueInstance已經不為空,跳出同步塊。接著3進入,又跳出同步塊。
??volatile關鍵字確保:當uniqueInstance變量被初始化成Singleton實例時,多個線程正確地uniqueInstance變量。如果性能是你關心的重點,那么這個做法可以幫你大大地減少getInstance()的時間耗費。
??最后給一個完整的demo:

package com.gqz.thread; /** 單例模式:懶漢式套路 在多線程環境下 對外存在一個對象* 1、構造器私有化 --> 避免外部 new構造器* 2、提供私有地屬性 --> 存儲對象的地址* 3、提供公共的靜態方法--->獲取屬性*/ public class DoubleCheckedLocking {//2、提供私有地屬性//直接new對象了是餓漢式 沒有new的事懶漢式//volatile其他線程可能訪問一個沒有初始化的對象private static volatile DoubleCheckedLocking instance; //1、構造器私有化private DoubleCheckedLocking() {}//3、提供公共的靜態方法-->獲取屬性public static DoubleCheckedLocking getInstance() {//再次檢測if (null != instance) { //避免不必要的同步,如果已經存在對象return instance;}//防止多個線程 需要加上鎖 synchronizedsynchronized (DoubleCheckedLocking.class) {if (null == instance) {instance = new DoubleCheckedLocking();/** //創建對象 可能存在指令重排* 1、開辟空間 2、初始化對象信息 3、返回對象的地址給引用*/}}return instance;}public static void main(String[] args) {Thread thread = new Thread(()->{System.out.println(DoubleCheckedLocking.getInstance());});thread.start();System.out.println(DoubleCheckedLocking.getInstance());} } com.gqz.thread.DoubleCheckedLocking@816f27d com.gqz.thread.DoubleCheckedLocking@816f27d

??表明在多線程下,還是得到同一個單例對象。

總結

以上是生活随笔為你收集整理的多线程安全单例模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。