JVM并發編程AQSsync鎖ReentrantLock線程池ThreadLocal

并發編程2

    • synchronized鎖實現
    • **AQS**
    • **ReentrantLock實現**
    • **JUC 常用類**
    • 池的概念
  • ThreadLocal
    • ThreadLocal原理
    • 內存泄露
    • 強引用:
    • 軟引用
    • 弱引用
    • 虛引用
    • ThreadLocal內存泄露

synchronized鎖實現

synchronized是一個關鍵字,實現同步,還需要我們提供一個同步鎖對象,記錄鎖狀態,記錄線程信息

控制同步,是依靠底層的指令實現的.

如果是同步方法,在指令中會為方法添加ACC_SYNCHRONIZED標志

如果是同步代碼塊,在進入到同步代碼塊時,會執行monitorenter, 離開同步代碼塊時或者出異常時,執行monitorexit

AQS

AQS(AbstractQueuedSynchronizer 抽象同步隊列) 是一個實現線程同步的框架

并發包中很多類的底層都用到了AQS

class AbstractQueuedSynchronizer {private transient volatile Node head;private transient volatile Node tail;private volatile int state; //表示有沒有線程訪問共享數據  默認是0 表示沒有線程訪問//修改狀態的方法protected final boolean compareAndSetState(int expect, int update) {return unsafe.compareAndSwapInt(this, stateOffset, expect, update);}static final class Node {volatile Node prev;volatile Node next;volatile Thread thread;}}

ReentrantLock實現

ReentrantLock完全同過java代碼控制

 class ReentrantLock{abstract static class Sync extends AbstractQueuedSynchronizer {abstract void lock();}//非公平鎖static final class NonfairSync extends Sync {void lock(){}}//公平鎖static final class FairSync extends Sync {void lock(){}}}

在這里插入圖片描述

JUC 常用類

在集合類中,像Vector,Hashtable這些類加鎖時都是直接把鎖加載方法上了,性能就低, 在并發訪問量小的情況下,還可以使用, 大并發訪問量下,性能就太低了.

ConcurrentHashMap

 HashMap適合單線程場景下的,不允許多個線程同時訪問操作,如果有多線程訪問會報異常Hashtable 是線程安全的 直接給方法加鎖,效率低ConcurrentHashMap 是線程安全的,沒有直接給方法加鎖, 用哈希表中每一個位置上的第一個元素(第一個是存在元素)作為鎖對象哈希表長度是16,那么就有16把鎖對象,鎖住自己的位置即可,這樣如果多個線程如果操作不同的位置,那么相互不影響,只有多個線程操作同一個位置時,才會等待如果位置上沒有任何元素,那么采用cas機制插入數據到對應的位置Hashtable ,ConcurrentHashMap  鍵值都不能為null為什么這樣設計,鍵值都不能為null?map.put("b","b")為了消除歧義  System.out.println(map1.get("a"));//null  值是null  還是鍵不存在返回null

CopyOnWriteArrayList

ArrayList 是單線程場景下使用的,在多線程場景下會報異常
Vector 是線程安全的,在方法上加了鎖,效率低
CopyOnWriteArrayList  寫方法操作加了鎖(ReentrantLock實現的),
在寫入數據時,先把原數組做了備份,把要添加的數據寫入到備份數組中,當寫入完成后,再把修改的數組賦值到原數組中去
給寫加了鎖,讀沒有加鎖,讀的效率變高了, 這種適合寫操作少,讀操作多的場景

CopyOnWriteArraySet

CopyOnWriteArraySet 的實現基于 CopyOnWriteArrayList,不能存儲重復數據。

輔助類 CountDownLatch

池的概念

字符串常量池

String s1 = “abc”; String s2=“abc”; s1==s2//true

Integer自動裝箱 緩存了-128 --+127之間的對象

Integer a = 100; Integer b = 100; a==b //true IntegerCache.cache[i + (-IntegerCache.low)];

數據庫連接池

阿里巴巴Druid數據庫連接池

幫我們緩存一定數量的鏈接對象,放在池子里,用完還回到池子中,

減少了對象的頻繁創建和銷毀的時間開銷

線程池

在這里插入圖片描述

為減少頻繁的創建和銷毀線程,

jdk5開始引入了線程池,

建議使用ThreadPoolExecutor類來創建線程池, 這樣提高效率.

Java.uitl.concurrent.ThreadPoolExecutor

 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

7個參數

corePoolSize: 核心線程池中的數量(初始化的數量) 5

maximumPoolSize:線程池中最大的數量 10 5

keepAliveTime: 空閑線程存活時間 當核心線程池中的線程足以應付任務時, 非核心線程池中的線程在指定空閑時間到期后,會銷毀.

unit: 時間單位

workQueue: 5 等待隊列, 當核心線程池中的線程都在使用時,如果有任務繼續到來,會先將等待的任務放到隊列中,如果隊列也滿了,才會創建新的線程(非核心線程池中的線程)

threadFactory:線程工廠,用來創建線程池中的線程

handler:拒絕處理任務時的策略 4種拒絕策略

線程池工作流程

當有大量的任務到來時,先判斷核心線程池中的線程是否都忙著,

? 有空閑的,直接讓核心線程中的線程執行任務

? 沒有空閑的, 判斷等待隊列是否已滿,

? 如果沒滿,把任務添加到隊列等待

? 如果已滿,判斷非核心線程池中的線程是否都忙著

? 如果有空閑的,沒滿,交由非核心線程池中的線程執行

? 如果非核心線程池野已經滿了,那么就使用對應的拒絕策略處理.

4種拒絕策略:

AbortPolicy: 拋異常

CallerRunsPolicy: 由提交任務的線程執行 例如在main線程提交,則由main線程執行拒絕的任務 DiscardOldestPolicy: 丟棄等待時間最長的任務

DiscardPolicy: 丟棄最后不能執行的任務

提交任務的方法

void   execute(任務);  提交任務沒有返回值Future<?> submit = executor.submit(myTask);//提交任務可以接收返回值
submit.get();  

關閉線程池

shutdown();  執行shutdown()后,不再接收新的任務,會把線程池中還有等待隊列中已有的任務執行完,再停止
shutdownNow(); 立即停止,隊列中等待的任務就不再執行了.
  如果有空閑的,沒滿,交由非核心線程池中的線程執行

? 如果非核心線程池野已經滿了,那么就使用對應的拒絕策略處理.

4種拒絕策略:

AbortPolicy: 拋異常

CallerRunsPolicy: 由提交任務的線程執行 例如在main線程提交,則由main線程執行拒絕的任務 DiscardOldestPolicy: 丟棄等待時間最長的任務

DiscardPolicy: 丟棄最后不能執行的任務

提交任務的方法

void   execute(任務);  提交任務沒有返回值Future<?> submit = executor.submit(myTask);//提交任務可以接收返回值
submit.get();  

關閉線程池

shutdown();  執行shutdown()后,不再接收新的任務,會把線程池中還有等待隊列中已有的任務執行完,再停止
shutdownNow(); 立即停止,隊列中等待的任務就不再執行了.

ThreadLocal

ThreadLocal中填充的變量屬于當前線程,改變量對其他線程而言是隔離的
ThreadLocak為變量在每個線程創建了一個副本,每個線程可以訪問自己內部的副本變量

static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){
@Overrideprotected Integer initialValue() {return 1;}
};

ThreadLocal原理

首 先 ThreadLocal 是 一 個 泛 型 類 , 保 證 可 以 接 受 任 何 類 型 的 對 象 ,ThreadLocal 內 部 維 護 了 一 個 Map , ThreadLocal 實 現 了 一 個 叫做 ThreadLocalMap 的靜態內部類。
而我們使用的 get()、set() 方法其實都是由這個 ThreadLocalMap 類對應的 get()、set() 方法實現的。首 先 ThreadLocal 是 一 個 泛 型 類 , 保 證 可 以 接 受 任 何 類 型 的 對 象 。

在這里插入圖片描述
在這里插入圖片描述
最終變量是放在當前線程的ThreadLocalMap中,并不是存在ThreadLocal上,ThreadLocal主要作為key,用于存讀操作

內存泄露

當對象已經不再被引用,但是垃圾回收機制無法回收該對象,就會產生內存泄露問題(例如數據庫鏈接對象,流對象,socker)

強引用:

當內存不足,JVM開始垃圾回收,對于強引用的對象,就算是出現了OOM也不會對該對象進行回收,死都不收。

強引用是我們最常見的普遍對象引用,只要還有強引用指向一個對象,就能表明對象還活著,垃圾收集器不會碰這種對象。在JAVA最常見的就是強引用,把一個對象賦給一個引用變量就是一個強引用。當一個對象被強引用變量引用時,它處于可達狀態,它是不可能被垃圾回收機制回收的,即使該對象以后永遠都不會被用到JVM也不會回收,因此強引用時造成Java內存泄漏的主要原因之一。

對于一個普通的對象,如果沒有其他的引用關系,只要超過了引用的作用域或者顯式地將相應(強)引用復制為null,一版認為就是可以背垃圾收集了。

public class StrongReferenceDemo {public static void main(String []args) {Object obj1 = new Object(); //這樣定義默認是強引用Object obj2 = obj1;obj1 = null;System.gc();System.out.println(obj1);System.out.println(obj2);}
}

對象如果有強引用關系,必定不會被回收

軟引用

軟引用是一種相對強引用弱化了一些的引用,需要用java.lang.ref.SoftReference類來實現,可以讓對象豁免一些垃圾收集,對于只有軟引用的對象來說,

當系統內存充足時它不會被回收,當系統內存不足時它會被回收。

軟引用通常用在對內存敏感的程序中,比如高速緩存就有用到軟引用,內存夠用的時候就保留,不夠用就回收!

public class SoftReferenceDemo {public static void main(String []args) {Object o1 = new Object();SoftReference<Object> softReference = new SoftReference<Object>(o1);System.out.println(o1);System.out.println(softReference.get());o1 = null;System.gc();try {byte[] bytes = new byte[30*1024*1024];} finally {System.out.println(o1);System.out.println(softReference.get());}}
}

弱引用

弱引用需要用java.lang.ref.WeakReference類來實現,它比軟引用的生存區更短。

對于只有弱引用的對象來說,只要垃圾回收機制一運行,不管JVM的內存空間是否足夠,都會回收該對象占用的內存。

public class WeakReferenceDemo {public static void main(String[] args) {Object o1 = new Object();WeakReference<Object> weakReference = new WeakReference<Object>(o1);System.out.println(o1);System.out.println(weakReference.get());o1 = null;System.gc();System.out.println("----------------------------");System.out.println(o1);System.out.println(weakReference.get());}
}

虛引用

虛引用需要java.lang.ref.PhantomReference類來實現。

顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用并不會決定對象的生命周期。

如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時間都可能被垃圾回收

器回收,它不能單點使用也不能通過它訪問對象,虛引用必須和引用隊列(ReferenceQueue)聯合使用。

虛引用的主要作用是跟蹤對象被垃圾回收的狀態,僅僅是提供了一種確保對象被finalize以后,做某些事情的機制。PhantomReference的get方法總是返回null,因此無法訪問對應的引用對象,其意義在于說明一個對象已經進入了finalization階段,可以被gc回收,用來實現比finalization機制更靈活的回收操作。

換句話說,設置虛引用關聯的唯一目的,就是在這個對象被收集器回收的時候收到一個系統通知或者后續添加進一步的處理。Java技術允許使用fianlize()方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作

public class PhantomReferenceDemo {public static void main(String []args) throws Exception {Object o1 = new Object();ReferenceQueue<Override> referenceQueue = new ReferenceQueue<>();PhantomReference<Object> phantomReference = new PhantomReference(o1,referenceQueue);System.out.println(o1);System.out.println(phantomReference.get());System.out.println(referenceQueue.poll());System.out.println("-----------------");o1 = null;System.gc();Thread.sleep(500);System.out.println(o1);System.out.println(phantomReference.get());System.out.println(referenceQueue.poll());}
}

ThreadLocal內存泄露

在這里插入圖片描述
TreadLocalMap 使用 ThreadLocal 的弱引用作為 key,如果一個 ThreadLocal不存在外部強引用時,Key(ThreadLocal)勢必會被 GC 回收,這樣就會導致ThreadLocalMap 中 key 為 null, 而 value 還存在著強引用,只有 thead 線程退出以后,value 的強引用鏈條才會斷掉。
但如果當前線程再遲遲不結束的話,這些 key 為 null 的 Entry 的 value 就會一直存在一條強引用鏈:
Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value

永遠無法回收,造成內存泄漏。
ThreadLocal 正確的使用方法
每次使用完 ThreadLocal 都調用它的 remove()方法清除數據。

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

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

相關文章

【JavaEE】網絡原理之初識

1.????前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 親愛的朋友們&#x1f44b;&#x1f44b;&#xff0c;這里是E綿綿呀????。 如果你喜歡這篇文章&#xff0c;請別吝嗇你的點贊????和收藏&#x1f4d6;&#x1f4d6;。如果你對我的…

操作系統-八股

進程基礎&#xff1a; 進程定義&#xff1a;運行中的程序&#xff0c;有獨立的內存空間和地址&#xff0c;是系統進行資源調度和分配的基本單位。 并發&#xff0c;并行 并發就是單核上面輪詢&#xff0c;并行就是同時執行&#xff08;多核&#xff09;&#xff1b; 進程上下…

ffmpeg面試題整理

1. 基礎概念 問題&#xff1a;FFmpeg 是什么&#xff1f;它的核心功能有哪些&#xff1f; 編解碼&#xff1a;支持幾乎所有音視頻格式&#xff08;如 H.264, AAC, MP3&#xff09;。轉換&#xff1a;在不同容器格式之間轉換&#xff08;如 MP4 → MKV&#xff09;。流處理&…

chrome瀏覽器插件拓展捕獲頁面的響應體內容

因為chrome extension官方沒有的直接獲取響應體的方法&#xff0c;所以需要自己實現方法來獲取&#xff0c;實現的方式有很多種&#xff0c;這是記錄的第二種&#xff0c;第一種就是使用vconsole來實現&#xff0c;vconsole是一個開源框架&#xff0c;一個輕量、可拓展、針對手…

探索天然分子swertiamarin調控脂肪生成的新機制

隨著生活方式的改變和環境的惡化&#xff0c;糖尿病這一全球性健康挑戰日益嚴峻。據世界衛生組織統計&#xff0c;全球糖尿病患者數量不斷攀升&#xff0c;其中2型糖尿病&#xff08;T2DM&#xff09;占據了絕大多數。T2DM不僅影響患者的生活質量&#xff0c;還給醫療系統帶來了…

沐數科技數據開發崗筆試題2025

描述性統計 標準差 答案: A 解析: 標準差 衡量數據集中數值變化或離散程度的一種度量。它反映了數據集中的各個數值與數據集的平均值&#xff08;均值&#xff09;之間的偏離程度。標準差越大&#xff0c;表明數據的分布越分散&#xff1b;標準差越小&#xff0c;表明數據…

Java 集合遍歷過程中修改數據觸發 Fail-Fast 機制 ,導致報ConcurrentModificationException異常

Java Fail-Fast 機制 Fail-Fast 機制是 Java 集合框架中的一種錯誤檢測機制&#xff0c;用于在遍歷集合時檢測結構修改。如果在迭代器創建之后&#xff0c;集合被修改&#xff08;例如添加或刪除元素&#xff09;&#xff0c;并且這種修改不是通過迭代器自身的 remove() 方法進…

Qt-ZMQ的使用補充(pub-sub)

之前寫過一篇Qt使用ZMQ的博客Qt網絡編程-ZMQ的使用&#xff0c;本文是其的補充部分。 Linux上編譯使用 首先這次實在Linux上進行演示&#xff0c;下載zmq源碼&#xff0c;安裝cmake&#xff0c;使用cmake進行編譯。下載之后解壓&#xff1a; 輸入命令&#xff1a; cd ..mkdi…

C++的名稱空間

C++的名稱空間(namespace)是一種用于組織代碼、防止命名沖突的機制。以下是名稱空間的詳細說明和使用建議: 1. 名稱空間的定義 使用namespace關鍵字定義,內部可包含變量、函數、類等: namespace MyNamespace {int a;void func() {} }2. 訪問方式 作用域解析運算符:::顯…

記錄致遠OA服務器硬盤升級過程

前言 日常使用中OA系統突然卡死&#xff0c;刷新訪問進不去系統&#xff0c;ping服務器地址正常&#xff0c;立馬登錄服務器檢查&#xff0c;一看磁盤爆了。 我大腦直接萎縮了&#xff0c;誰家OA系統配400G的空間啊&#xff0c;過我手的服務器沒有50也是30臺&#xff0c;還是…

[測試]自動化的概念 及使用Selenium實現Web自動化測試

文章目錄 1. 自動化1.1 自動化概念1.2 自動化分類1.2.1 接口自動化1.2.2 UI自動化 1.3 自動化測試金字塔 2. Web自動化測試2.1 驅動 3. Selenium3.1 一個簡單的Web自動化示例3.2 Selenium 驅動 瀏覽器的工作原理 1. 自動化 1.1 自動化概念 自動化是指自動地代替人的行為完成…

Python教程(三):類對象、閉包、裝飾器、類型注解、MRO

Python總結&#xff08;三&#xff09; 本系列其他教程&#xff1a; Python教程(一)&#xff1a;基本語法、流程控制、數據容器 Python教程(二)&#xff1a;函數、異常、模塊&包、文件讀取、常用模塊 文章目錄 Python總結&#xff08;三&#xff09;一、類&對象1.1 成…

什么是 HTML?

HTML 是用來描述網頁的一種語言。 HTML 指的是超文本標記語言: HyperText Markup LanguageHTML 不是一種編程語言&#xff0c;而是一種標記語言標記語言是一套標記標簽 (markup tag)HTML 使用標記標簽來描述網頁HTML 文檔包含了HTML 標簽及文本內容HTML文檔也叫做 web 頁面 HT…

【Hadoop】Hadoop的簡要介紹

Hadoop是一個由Apache基金會所開發的分布式系統基礎架構&#xff0c;主要用于解決海量數據的存儲及分析計算問題。以下是對Hadoop的詳細介紹&#xff1a; 目錄 一、Hadoop的起源與發展 二、Hadoop的核心組件 1.HDFS&#xff1a; 2.MapReduce&#xff1a; 3.YARN&#xff…

如何用AI制作PPT,輕松實現高效演示

如何用AI制作PPT&#xff0c;輕松實現高效演示&#xff01;在今天這個快節奏的時代&#xff0c;我們的工作方式越來越依賴智能工具。而當涉及到演示文稿時&#xff0c;傳統的PPT制作方式往往繁瑣且耗時。很多人一提到制作PPT就頭大&#xff0c;特別是在內容需要多次修改、調整布…

Canoe Panel基礎功能介紹

文章目錄 一、新建 Panel 面板二、添加 Panel 面板三、刪除 Panel 面板四、Panel視圖&#xff08;views&#xff09;五、控件布局1. 對齊布局2. 控件大小布局 六、Panel 屬性設置1. 設置背景色和背景圖片2. 調整 Panel 畫布大小 提示&#xff1a;如何使用 Panel 面板參考 CANoe…

超聲重建,3D重建 超聲三維重建,三維可視化平臺 UR 3D Reconstruction

1. 超聲波3D重建技術的實現方法與算法 技術概述 3D超聲重建是一種基于2D超聲圖像生成3D體積數據的技術&#xff0c;廣泛應用于醫學影像領域。通過重建和可視化三維結構&#xff0c;3D超聲能夠顯著提高診斷精度和效率&#xff0c;同時減少醫生的腦力負擔。本技術文檔將詳細闡述…

2.2 企業級ESLint/Prettier規則定制

文章目錄 1. 為什么需要企業級代碼規范2. 工具選型對比3. 完整配置流程3.1 項目初始化3.2 ESLint深度配置3.3 Prettier精細配置3.4 解決規則沖突4. 高級定制方案4.1 自定義ESLint規則4.2 擴展Prettier插件5. 團隊協作策略5.1 配置共享方案5.2 版本控制策略6. CI/CD集成7. 常見問…

QT創建項目(項目模板、構建系統、選擇類、構建套件)

1. 項目模版 項目類型界面技術適用場景核心依賴模塊開發語言Qt Widget ApplicationC Widgets傳統桌面應用&#xff08;復雜控件&#xff09;Qt WidgetsCQt Console Application無 GUI命令行工具、服務Qt CoreCQt Quick ApplicationQML/Quick現代跨平臺應用&#xff08;動畫/觸…

oracle11.2.0.4 RAC 保姆級靜默安裝(二) DB數據庫軟件

1.響應文件配置 [rootdb11g1 software]# su - oracle [oracledb11g1 ~]$ cd /software/database/ [oracledb11g1 database]$ cd response/ [oracledb11g1 response]$ vi db_install.rsp oracle.install.optionINSTALL_DB_SWONLY ORACLE_HOSTNAMEdb11g1 UNIX_GROUP_NAME…