java線程安全-單例模式-線程通信

首先看看單例模式的寫法

首先我們先來回顧一下餓漢式單例模式:

class Singleton{private static Singleton singleton=new Singleton();private Singleton(){}public static Singleton getInstrance(){return singleton;}
}
public class Test{public static void main(String[] args){Singleton singleton=Singleton.getInstrance();}
}

??????餓漢式是在類加載的時候創建實例,故不存在線程安全問題。
虛擬機會保證一個類的<clinit>()方法在多線程環境中被正確地加鎖、同步,如果多個線程同時去初始化一個類,那么只會有一個線程去執行這個類的<clinit>()方法,其他線程都需要阻塞等待,直到活動線程執行<clinit>()方法完畢。
??????不用我們手工去保證線程安全問題

public class Demo1 {public static void main(String[] args){for(int i=0;i<10;i++) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Singleton.getInstrance());}}).start();}}}
class Singleton{private static Singleton singleton=new Singleton();private Singleton(){System.out.println("我是餓漢模式");}public static Singleton getInstrance(){return singleton;}
}
---------------------------------------------------------------------------------
我是餓漢模式,創建的10個對象是同一個對象
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f
cn.xiong.demo.sychnoized.singleton.Singleton@23b1870f

優點:
類加載時完成初始化,獲取對象的速度較快.
缺點:
類加載較慢.

懶漢式單例模式可以這樣寫:

class Singleton{private static Singleton singleton = null;private Singleton(){}public static Singleton getInstrance(){if(singleton==null){singleton=new Singleton;}return singleton;}
}
-----------------------------------------------------------------------
cn.xiong.demo.sychnoized.singleton.SingleTon2@56f2a97e
cn.xiong.demo.sychnoized.singleton.SingleTon2@56f2a97e
cn.xiong.demo.sychnoized.singleton.SingleTon2@56f2a97e
cn.xiong.demo.sychnoized.singleton.SingleTon2@56f2a97e
cn.xiong.demo.sychnoized.singleton.SingleTon2@2e3a9cb1
cn.xiong.demo.sychnoized.singleton.SingleTon2@56f2a97e
cn.xiong.demo.sychnoized.singleton.SingleTon2@56f2a97e
cn.xiong.demo.sychnoized.singleton.SingleTon2@56f2a97e
cn.xiong.demo.sychnoized.singleton.SingleTon2@56f2a97e  //下面有一個不同于上面的對象
cn.xiong.demo.sychnoized.singleton.SingleTon2@7b69b864

??????現在我們學習多線程相關知識,就很容易能夠發現上述懶漢式單例模式為什么線程不安全了。假設開始線程0進入,判斷singleton為空,在將要創建實例時,cpu切換,
線程1又進來了,同樣singleton為空 創建了實例,這是cpu切換回來到0線程,繼續創建實例
可見,經過分析共創建了 兩個實例,還談什么單例。

怎么才能使懶漢式單例模式線程安全呢?

1.synchronized,volatile雙層鎖處理

public class Demo2 {public static void main(String[] args) {for(int i=0;i<10;i++) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println(SingleTon2.getInstance());}}).start();}}}class SingleTon2{private volatile static SingleTon2 singleton=null;    //第二層鎖,volatile關鍵字讓內存是否可見有關private SingleTon2() {}public static SingleTon2 getInstance() {if(singleton == null) {    //第一層檢查,檢查是否有引用指向對象,高并發情況下會有多個線程同時進入synchronized (SingleTon2.class) {  //第一層鎖,保證只有一個線程進入,其它線程等執行完畢if(singleton ==null)    //第二層檢查,那么第一個線程創建完對象釋放鎖后,volatile保證了singleton 可見,第二個線程就進不去了singleton = new SingleTon2();}}return singleton;}
}

2.靜態內部類

public class StaticInnerClassChuli {public static void main(String[] args) {for(int i=0;i<10;i++) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Singleton3.getInstance());}}).start();}}}class Singleton3{private Singleton3() {}//靜態內部類private static class SingleTonHoler{private static Singleton3 singleton3 = new Singleton3();}public static Singleton3 getInstance() {return SingleTonHoler.singleton3;}}

靜態內部類的優點是:外部類加載時并不需要立即加載內部類,內部類不被加載則不去初始化INSTANCE,故而不占內存。
??????只有當getInstance()方法第一次被調用時,才會去初始化INSTANCE,第一次調用getInstance()方法會導致虛擬機加載SingleTonHoler類,這種方法不僅能確保線程安全,也能保證單例的唯一性,同時也延遲了單例的實例化。

??????同上面說的餓漢模式創建靜態對象一樣,類加載時, 虛擬機會保證一個類的<clinit>()方法在多線程環境中被正確地加鎖、同步,如果多個線程同時去初始化一個類,那么只會有一個線程去執行這個類的()方法,其他線程都需要阻塞等待,直到活動線程執行<clinit>()方法完畢。
??????那么,是不是可以說靜態內部類單例就是最完美的單例模式了呢?其實不然,靜態內部類也有著一個致命的缺點,就是傳參的問題,由于是靜態內部類的形式去創建單例的,故外部無法傳遞參數進去,所以,我們創建單例時,可以在靜態內部類與懶漢式模式里自己斟酌。
3.枚舉類的形式

public class EnumSingleChuli {public static void main(String[] args) {for(int i=0;i<10;i++) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Singleton4.INSTANCETON);System.out.println(Singleton4.getInstance());}}).start();}}}enum Singleton4{INSTANCETON;public static Singleton4 getInstance() {return Singleton4.INSTANCETON;}
}

枚舉單例模式在《Effective Java》中推薦的單例模式之一。但本人還是喜歡在餓漢模式或靜態內部類方法中選擇來用

線程通信

??????在前面我們講了很多關于同步的問題,然而在現實開發中,是需要線程之間的協作,也就是需要線程之間實現通信的。

先了解一下最經典的程序設計模式之一的生產者-消費者模型
??????日常生活中,每當我們缺少某些生活用品時,我們都會去超市進行購買,那么,你有沒有想過,你是以什么身份去的超市呢?相信大部分人都會說自己是消費者,確實如此,那么既然我們是消費者,又是誰替我們生產各種各樣的商品呢?當然是超市的各大供貨商,自然而然地也就成了我們的生產者。
??????如此一來,生產者有了,消費者也有了,那么將二者聯系起來的超市又該作何理解呢?
??????誠然,它本身是作為一座交易場所而誕生。

??????將上述場景類比到我們實際的軟件開發過程中,經常會見到這樣一幕:
代碼的某個模塊負責生產數據(供貨商),
??????而生產出來的數據卻不得不交給另一 模塊(消費者) 來對其進行處理,
在兩個程序模塊之間我們必須要有一個類似上述超市的東西來存儲數據(超市),這就抽象出了我們的 生產者/消費者模型

其中,產生數據的模塊,就形象地稱為生產者;
而處理數據的模塊,就稱為消費者;
生產者和消費者之間的中介就叫做緩沖區,一般就是一個隊列。

在生產者-消費者模型中,當隊列滿時,生產者需要等待隊列有空間才能繼續往里面放入商品,而在等待的期間內,生產者必須釋放對隊列的占用權。因為生產者如果不釋放對隊列的占用權,那么消費者就無法消費隊列中的商品,就不會讓隊列有空間,那么生產者就會一直無限等待下去。
??????因此,一般情況下,當隊列滿時,會讓生產者交出對隊列的占用權,并進入掛起狀態。然后等待消費者消費了商品,然后消費者通知生產者隊列有空間了。
??????同樣地,當隊列空時,消費者也必須等待,等待生產者通知它隊列中有商品了。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/76149.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76149.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/76149.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大數據技術之SPARK

Spark Core 什么是 RDD 代碼中是一個抽象類&#xff0c;它代表一個彈性的、不可變、可分區、里面的元素可并行計算的集合 彈性 存儲的彈性&#xff1a;內存與磁盤的自動切換&#xff1b; 容錯的彈性&#xff1a;數據丟失可以自動恢復&#xff1b; 計算的彈性&#xff1a;…

Go 語言范圍 (Range)

Go 語言范圍 (Range) Go 語言是一種靜態強類型、編譯型、并發型編程語言&#xff0c;由 Google 開發。它的簡潔性和高效性使其成為眾多開發者的首選。在 Go 語言中&#xff0c;range 是一個非常有用的關鍵字&#xff0c;用于遍歷數組、切片、字符串以及通道&#xff08;channe…

VUE中數據綁定之OptionAPI

<template> <div> 姓名:<input v-model="userName" /> {{ userName }} <br /> 薪水:<input type="number" v-model="salary" /> <br /> <button v-on:click="submit">提交</button>…

react動態路由

框架的權限控制&#xff08;在config.ts中配置&#xff09; export default {access: {}, }; 權限配置文件&#xff08;access.ts&#xff09; 新建 src/access.ts &#xff0c;在該文件中 export default 一個函數&#xff0c;定義用戶擁有的權限 該文件需要返回一個 functi…

Android里面如何優化xml布局

在 Android 開發中&#xff0c;以下是系統化的優化方案&#xff0c;從基礎到高級分層解析&#xff1a; 一、基礎優化策略 1. 減少布局層級 問題&#xff1a;每增加一層布局&#xff0c;測量/布局時間增加 1-2ms 解決方案&#xff1a; <!-- 避免嵌套 --> <LinearLayo…

基于STM32、HAL庫的IP6525S快充協議芯片簡介及驅動程序設計

一、簡介: IP6525S是一款高性能的同步降壓DC-DC轉換器芯片,具有以下特點: 輸入電壓范圍:4.5V至32V 輸出電壓范圍:0.8V至30V 最大輸出電流:5A 效率高達95% 可編程開關頻率(100kHz-1MHz) 支持PWM和PFM模式 內置過流保護、過溫保護等功能 該芯片常用于工業控制、通信設備…

二分算法的入門筆記

二分查找 使用前提&#xff1a;有序。可理解為枚舉的一種技巧。時間復雜度&#xff1a; l o g ( n ) log(n) log(n) 基礎模版代碼 使用時根據情景進行相應的變化。注意跳出條件and分支處理方式and返回答案&#xff0c;三者之間的配合&#xff0c;不要進入死循環。可以在模擬…

輕量級Java跨包調用(完全解耦)

Java函數式命令模式 輕量級跨包調用解耦方案&#xff0c;讓跨包調用就像調用本地接口那樣簡單。適用與具有公共依賴的兩個jar包&#xff0c;但是又不想相互引入對方作為依賴。 函數式命令模式&#xff0c;很好地實現了跨包調用解耦的目標&#xff0c;并且通過泛型JSON動態轉換保…

離散數學問題集--問題5.9

問題 5.9 綜合了計算機組成原理、數字邏輯和離散數學中的關鍵概念&#xff0c;旨在幫助學生理解二進制算術運算的硬件實現、邏輯門與算術運算的關系&#xff0c;以及如何使用數學方法來驗證數字系統的正確性。它強調了從規范到實現再到驗證的完整過程。 思想 函數抽象&#xf…

OpenLayers:海量圖形渲染之矢量切片

最近由于在工作中涉及到了海量圖形渲染的問題&#xff0c;因此我開始研究相關的解決方案。在咨詢了許多朋友之后發現矢量切片似乎是行業內最常用的一種解決方案&#xff0c;于是我便開始研究它該如何使用。 一、什么是矢量切片 矢量切片按照我的理解就是用柵格切片的方式把矢…

神經網絡入門—自定義網絡

網絡模型 定義一個兩層網絡 import torch import torch.nn as nn import torch.optim as optim import torch.nn.functional as F# 定義神經網絡模型 class Net(nn.Module):def __init__(self, init_x0.0):super().__init__()self.fc1 nn.Linear(1, 10)self.fc2 nn.Linear(…

無人機裝調與測試

文章目錄 前言一、無人機基本常識/預備知識&#xff08;一&#xff09;無人機飛行原理無人機硬件組成/各組件作用1.飛控2.GPS3.接收機4.電流計5.電調6.電機7.電池8.螺旋槳9.UBEC&#xff08;穩壓模塊&#xff09; &#xff08;二&#xff09;飛控硬件簡介&#xff08;三&#x…

2024年-全國大學生數學建模競賽(CUMCM)試題速瀏、分類及淺析

2024年-全國大學生數學建模競賽(CUMCM)試題速瀏、分類及淺析 全國大學生數學建模競賽&#xff08;China Undergraduate Mathematical Contest in Modeling&#xff09;是國家教委高教司和中國工業與應用數學學會共同主辦的面向全國大學生的群眾性科技活動&#xff0c;目的在于激…

Linux入門指南:從零開始探索開源世界

&#x1f680; 前言 大家好&#xff01;今天我們來聊一聊Linux這個神奇的操作系統~ &#x1f916; 很多小伙伴可能覺得Linux是程序員專屬&#xff0c;其實它早已滲透到我們生活的各個角落&#xff01;本文將帶你了解Linux的誕生故事、發行版選擇攻略、應用領域&#xff0c;還有…

記錄vscode連接不上wsl子系統下ubuntu18.04問題解決方法

記錄vscode連接不上wsl子系統下ubuntu18.04問題解決方法 報錯內容嘗試第一次解決方法嘗試第二次解決方法注意事項參考連接 報錯內容 Unable to download server on client side: Error: Request downloadRequest failed unexpectedly without providing any details… Will tr…

Cursor+MCP學習記錄

參考視頻 Cursor MCP 王炸&#xff01;徹底顛覆我的Cursor工作流&#xff0c;效率直接起飛_嗶哩嗶哩_bilibili 感覺這個博主講的還不錯 所使用到的網址 Smithery - Model Context Protocol Registry Introduction - Model Context Protocol 學習過程 Smithery - Model …

testflight上架ipa包-只有ipa包的情況下如何修改簽名信息為蘋果開發者賬戶對應的信息-ipa蘋果包如何手動改簽或者第三方工具改簽-優雅草卓伊凡

testflight上架ipa包-只有ipa包的情況下如何修改簽名信息為蘋果開發者賬戶對應的信息-ipa蘋果包如何手動改簽或者第三方工具改簽-優雅草卓伊凡 直接修改蘋果IPA包的簽名和打包信息并不是一個推薦的常規做法&#xff0c;因為這可能違反蘋果的開發者條款&#xff0c;并且可能導致…

深入解析Java內存與緩存:從原理到實踐優化

一、Java內存管理&#xff1a;JVM的核心機制 1. JVM內存模型全景圖 ┌───────────────────────────────┐ │ JVM Memory │ ├─────────────┬─────────────────┤ │ Thread │ 共享…

紫光展銳5G SoC T8300:影像升級,「定格」美好世界

影像能力已成為當今衡量智能手機性能的重要標尺之一。隨著消費者對手機攝影需求日益提升&#xff0c;手機廠商紛紛在影像硬件和算法上展開激烈競爭&#xff0c;力求為用戶帶來更加出色的拍攝體驗。 紫光展銳專為全球主流用戶打造的暢享影音和游戲體驗的5G SoC——T8300&#x…

【Java設計模式】第6章 抽象工廠模式講解

6. 抽象工廠模式 6.1 抽象工廠講解 定義:提供一個接口創建一系列相關或依賴對象,無需指定具體類。核心概念: 產品等級結構:同一類型的不同產品(如Java視頻、Python視頻)。產品族:同一工廠生產的多個產品(如Java視頻 + Java手記)。適用場景: 需要創建多個相關聯的產品…