java 同步 lock_關于java:同步是否像Lock.lock()一樣駐留并發線程?

當我們調用lock.lock()或嘗試輸入synchronized塊時,如果其他某個線程已經獲得了該鎖,則我們的線程將阻塞。 現在我的問題是,當我們查看lock.lock()的實現時,它會將獲取鎖委托給AQS,而AQS實際將當前線程駐留在該線程中(因此調度程序無法對其進行進一步調度)。

synchronized阻塞是否也是如此?

我什至認為我的線程狀態也不同。 例如,如果我的線程在synchronized塊上被阻塞,則它將是BLOCKING,而如果我調用了

lock.lock(),則為WAITING。 我對嗎?

我關心的是以下兩種鎖定策略在Thread.status方面與通過停車而不是忙于等待來提高性能之間的區別

ReentrantLock.lock();

synchronize { /*some code */ }

抱歉,我從自動翻譯器回復。 我認為您應該附加示例代碼,這將幫助我們幫助您分析問題。 一般在使用同步時,可以不必鎖定。 鎖 ()。 一般來說,足夠同步。

調用lock或lockInterruptibly會將線程置于WAITING狀態:

Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:

Object.wait with no timeout

Thread.join with no timeout

LockSupport.park

以下代碼啟動四個線程,前兩個(A,B)運行相同的代碼,并通過lock方法鎖定某些監視器。 另外兩個(C,D)也運行相同的代碼,但是它們通過lockInterruptibly方法鎖定了另一個監視器:

public static synchronized void dumpThreadState(List threads) {

System.out.println("thread state dump start");

for (Thread t: threads) {

System.out.println(t.getName()+""+t.getState());

}

System.out.println("thread state dump end\

");

}

public static void main(String[] args) throws InterruptedException {

final Lock lock = new ReentrantLock();

final Lock anotherLock = new ReentrantLock();

List threads = new LinkedList();

Runnable first = new Runnable() {

@Override

public void run() {

try {

lock.lock();

}

catch (Exception ex) {

System.out.println(Thread.currentThread().getName()+" processing exception"+ex.getClass().getSimpleName());

}

while (true);

}

} ;

Runnable second = new Runnable() {

@Override

public void run() {

try {

anotherLock.lockInterruptibly();

}

catch (InterruptedException ex) {

System.out.println(Thread.currentThread().getName()+" was interrupted");

}

while (true);

}

};

threads.add(new Thread(first,"A"));

threads.add(new Thread(first,"B"));

threads.add(new Thread(second,"C"));

threads.add(new Thread(second,"D"));

dumpThreadState(threads);

for (Thread t: threads) {

t.start();

}

Thread.currentThread().sleep(100);

dumpThreadState(threads);

System.out.println("interrupting" + threads.get(1).getName());

threads.get(1).interrupt();

dumpThreadState(threads);

System.out.println("interrupting" + threads.get(3).getName());

threads.get(3).interrupt();

Thread.currentThread().sleep(100);

dumpThreadState(threads);

for (Thread t: threads) {

t.join();

}

}

它輸出:

thread state dump start

A NEW

B NEW

C NEW

D NEW

thread state dump end

thread state dump start

A RUNNABLE

B WAITING

C RUNNABLE

D WAITING

thread state dump end

interrupting B

thread state dump start

A RUNNABLE

B WAITING

C RUNNABLE

D WAITING

thread state dump end

interrupting D

D was interrupted

thread state dump start

A RUNNABLE

B WAITING

C RUNNABLE

D RUNNABLE

thread state dump end

可以看出,通過lock方法鎖定的線程不能被中斷,而通過lockInterruptibly鎖定的線程可以被中斷。

在另一個示例中,啟動了三個線程,前兩個(A,B)運行相同的代碼,并通過synchronized塊鎖定在同一監視器上。 第三個線程鎖定在另一個監視器上,但通過wait方法等待:

public static void main(String[] args) throws InterruptedException {

final Object lock = new Object();

final Object anotherLock = new Object();

List threads = new LinkedList();

Runnable first = new Runnable() {

@Override

public void run() {

synchronized(lock) {

while (true);

}

}

} ;

Runnable second = new Runnable() {

@Override

public void run() {

synchronized(anotherLock) {

try {

anotherLock.wait();

}

catch (InterruptedException ex) {

ex.printStackTrace();

}

}

}

};

threads.add(new Thread(first,"A"));

threads.add(new Thread(first,"B"));

threads.add(new Thread(second,"C"));

dumpThreadState(threads);

for (Thread t: threads) {

t.start();

}

Thread.currentThread().sleep(100);

dumpThreadState(threads);

for (Thread t: threads) {

t.join();

}

}

它輸出:

thread state dump start

A NEW

B NEW

C NEW

thread state dump end

thread state dump start

A RUNNABLE

B BLOCKED

C WAITING

thread state dump end

線程C以WAITING狀態結束,而線程B以BLOCKING狀態結束:

Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling Object.wait.

編輯:

這是一個非常好的線程狀態的UML圖。

阻止-在資源上被阻止,無法被中斷

等待-在資源上被阻止,但可以被中斷,通知或取消停放。

如您所見,Waiting更好地控制了另一個處理程序。例如如果兩個線程死鎖,則可以通過中斷來中斷lock()。使用同步的兩個線程時,您將陷入困境。

同步vs鎖定的行為非常相似,確切的細節在主要版本之間有所不同。

我的建議是使用

同步以獲取需要線程安全但鎖爭用非常低的簡單代碼。

在已確定有鎖爭用的地方使用Lock,或者需要其他功能,例如tryLock。

如果你這樣做

final Lock lock = new ReentrantLock();

lock.lock();

Thread t = new Thread(new Runnable() {

@Override

public void run() {

try {

lock.lockInterruptibly();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

t.start();

Thread.sleep(100);

System.out.println(t +" is" + t.getState());

lock.unlock();

版畫

Thread[Thread-0,5,main] is WAITING

Thread.State狀態

等待線程的線程狀態。由于調用以下方法之一,線程處于等待狀態:

Object.wait沒有超時

Thread.join沒有超時

LockSupport.park

處于等待狀態的線程正在等待另一個線程執行特定操作。例如,一個在對象上調用Object.wait()的線程正在等待另一個線程在該對象上調用Object.notify()或Object.notifyAll()。名為Thread.join()的線程正在等待指定的線程終止。

謝謝@Peter Lawrey,當線程被lock.lock()阻塞時,線程的狀態如何?

好的一點是,lock()將被阻塞,而lockInterruptably()將被等待,因為它可以被中斷。

@PeterLawrey調用鎖也會使線程也處于等待狀態

駐留線程和同步阻塞是非常不同的。嘗試輸入同步塊時,您將明確嘗試在對象實例上獲取監視器。如果無法獲取監視器,則線程將進入"阻塞"狀態,直到監視器可用為止。停放與Object.wait()方法更相似,因為代碼知道在其他條件變為真之前它不能繼續。阻止在這里是沒有意義的,因為這將是徒勞的,因為我目前繼續的條件是正確的。此時,我進入WAITING或TIMED_WAITING狀態(取決于等待的發出方式),直到被通知(通過類似notify(),notifyAll()或unpark()的通知)為止。一旦我的條件變為真,我就進入等待狀態,然后可能會嘗試獲取監視器并在需要時進入阻塞狀態。如果我得到顯示器,則進入"運行"并繼續快樂地前進

因此,等待實際上就是知道我無法做某事,并在認為可以的情況下讓其他線程通知我。我醒來后可能導致阻塞。阻塞只是爭奪對監視器的訪問,而沒有其他明確的先決條件。

在Lock實例上調用lock()時,調用線程實際上處于等待狀態,并且沒有阻塞。這樣做的好處是可以中斷此等待狀態,這有助于避免死鎖。對于類似Lock類的東西,您可以通過tryLock(),tryLock(long,TimeUnit),lock()和lockInterruptibly()來選擇所需的等待行為。您可以指定諸如要等待多長時間以及是否可以通過調用哪種方法打擾您之類的事情。使用synchronized代碼,您沒有此類選項。您正在阻塞,并且被阻塞阻塞,直到某個線程放棄了您想要的監視器為止,如果從未中斷,您將陷入僵局。這就是為什么從Java 5和concurrent包開始,您應該避免使用synchronized關鍵字,而是嘗試使用Lock和Condition之類的東西實現類似的語義。

謝謝@ cmbaxter,實際上我想問的是,當它調用Reentrantlock.lock()時,線程實際上進入了停車狀態。 這就是為什么我的問題在ReentrantLock.lock()中被阻止的原因實際上并未被阻止

是的,如果鎖當前不可用,則調用lock會將調用線程置于WAITING狀態。

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

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

相關文章

Idea項目中常見錯誤及筆記(Old)

1、Idea基礎設置: File-->settings--> 1>修改字體:Font 2>修改編碼格式:File Encodings(全部UTF-8,右下方復選框勾中--防止程序中的漢字轉為ASCII碼) 3>修改行號:Appearance:show line numbers show me…

java接口服務編排_GOKU API Gateway CE V3.1.0 發布:新增服務編排、配置版本管理等...

Goku API Gateway (中文名:悟空 API 網關)是一個基于 Golang 開發的微服務網關,能夠實現高性能 HTTP API 轉發、服務編排、多租戶管理、API 訪問權限控制等目的,擁有強大的自定義插件系統可以自行擴展,并且提供友好的圖形化配置界…

maxcompute 2.0復雜數據類型之array

2019獨角獸企業重金招聘Python工程師標準>>> 1. 含義 類似于Java中的array。有序、可重復。 2. 場景 什么樣的數據,適合使用array類型來存儲呢?這里列舉了幾個我在開發中實際用到的場景。 2.1 標簽類的數據 為什么說標簽類數據適合使用array類…

java中匿名數組_Swagger UI:數組中的多個匿名對象

對象數組的定義如下:type: arrayitems:type: objectproperties:prop1:type: stringprop2:type: integer# etc.在您的示例中,響應包含具有屬性 balanceDisplaySettings 的對象,并且此屬性包含對象數組 . 這可以定義如下:paths:/Pat…

java ioutils 寫入文件_文件輸入輸出流工具: IOUtils使用總結

序言以前寫文件的復制很麻煩,需要各種輸入流,然后讀取line,輸出到輸出流...其實apache.commons.io里面提供了輸入流輸出流的常用工具方法,非常方便。下面就結合源碼,看看IOUTils都有什么用處吧!常用的靜態變…

權限組件(6):權限分配的角色管理

效果圖: 為了方便開發,先把中間件注釋掉,要不還要在角色-權限表中添加對應關系。又因為二級菜單和面包屑導航需要中間件的變量,所以要在layout.html里面把這兩個也注釋掉。setting.py# rbac.middlewares.rbac.RbacMiddleware layo…

java 面試700問_JAVA面試700問(一)

1、Java環境中的字節碼是什么?由Java 編譯器生成的一種代碼。由JVM生成的一種代碼。Java源文件(Java Source File)的別名。一種寫在類的實例方法中的代碼。答案:由Java 編譯器生成的一種代碼。2、什么是Java垃圾回收機制?操作系統周期性的刪除…

02-Django基礎知識

一、內容回顧 1、web應用程序 2、HTTP協議 a、http協議特性 b、http請求格式 c、http響應格式 3、wsgiref模塊 4、Django下載與簡單應用 a、Django簡介(MTV) b、下載django命令 c、創建項目命令 d、創建app應用 e、啟動項目   二、今日概要 1、路由層&…

java條碼大小_java - ML Kit條形碼掃描:無效的圖像數據大小

我想在捕獲的圖像中檢測條形碼。我使用android的camera2捕獲圖像。此后,將檢索圖像的元數據并將圖像保存到設備。元數據全部傳遞到下一個活動,該活動是應用程序嘗試檢測條形碼的地方。下一個活動是從先前保存的文件創建一個byte []。接下來,使…

MongoDB數據庫泄露8億電郵地址;微軟開源Windows計算器;Linux 5.0 Kernel發布丨Q新聞...

本周要聞:華為正式宣布起訴美國政府;360 首席安全官譚曉生宣布離職;阿里開源 Flutter 應用框架 Fish Redux;微軟開源 Windows 計算器;Linux 5.0 Kernel 發布;電郵驗證服務泄漏 8 億電郵地址;Chr…

mysql 視圖 分頁_mysql查看所有存儲過程,函數,視圖,觸發器,表,分頁

查詢數據庫中的存儲過程和函數方法一:select name from mysql.proc where db your_db_name and type PROCEDURE //存儲過程select name from mysql.proc where db your_db_name and type FUNCTION //函數方法二:show procedure status; //存儲過程sh…

postman里測試文件上傳(MultipartFile)

1、后臺方法: Override PostMapping("/importNumberSpaceData") public DataImportOutDTO importNumberSpaceData(MultipartFile file) throws Exception { return dataImportOutDTO; } 2、啟用postman 1、POST方法; 2、Body-form-data,key為后…

java解析上的jar包里的pom_Maven引入本地Jar包并打包進War包中的方法

1.概述在平時的開發中,有一些Jar包因為種種原因,在Maven的中央倉庫中沒有收錄,所以就要使用本地引入的方式加入進來。2. 拷貝至項目根目錄項目根目錄即pom.xml文件所在的同級目錄,可以在項目根目錄下創建文件夾lib,如下…

持續集成之 Spring Boot 實戰篇

本文作者: CODING 用戶 - 何健 這次實戰篇,我們借助「CODING 持續集成」,實現一個簡單的 Spring Boot 項目從編碼到最后部署的完整過程。本教程還有 B 站視頻版,幫助讀者更好地學習理解。 思路 在線上環境構建、測試、部署 這種情…

java靜態工廠方法模式_設計模式:簡單工廠模式(靜態工廠方法模式)

簡單工廠的構成包括三個角色:1)抽象產品類2)具體產品類(繼承抽閑產品類)3)工廠類(生產具體產品)具體代碼實現1、抽象產品類/*** 抽象類*/public abstract class Car {/*** 產品抽象方法,將會由具體產品類實現*/public abstract void driving();}2、具體產…

Kibana中的Coordinate Map地圖報索引錯誤的問題

今天做地圖定位展示,展示的是ApacheWeb服務器的訪問日志文件中的來源IP。但是中間出現了報錯環節,說是索引不能匹配到geo_point類型,實在是不懂這是在說什么,后來在網站找了方法就解決了。主要報錯如下: 報錯信息&…

mysql數據庫安裝在unix_Linux下的數據庫二:在Linux/Unix平臺安裝MySQL

推薦使用RPM工具來進行Linux下的MySQL數據庫安裝。目前的MySQLrpm安裝文件包是在SuSE Linux7.3系統平臺上打造而成的,但是在絕大多數支持RPM和glibc的其他Linux平臺中也可以進行安裝。如果選擇通用的RPM安裝包,那么RPM將靜態鏈接到Linux的線程中。下面步…

mysql時區設置gmt_將MySQL數據庫時區設置為GMT

不,不可能在MySQL實例中更改單個數據庫的時區.您可以檢索服務器和客戶端time_zone設置:SELECT global.time_zone, session.time_zone;您還可以更改整個MySQL實例的客戶端時區或時區.但要敏銳地了解現有客戶端連接的含義,以及如何解釋已存儲在實例中的DATETIME和TIME…

javaSE知識點匯總

javaSE知識點匯總Java基礎知識精華部分寫代碼:1,明確需求。我要做什么?2,分析思路。我要怎么做?1,2,3。3,確定步驟。每一個思路部分用到哪些語句,方法,和對象。4,代碼實現…

java中412是什么錯_HTTP 412 錯誤 – 先決條件失敗 (Precondition failed)

HTTP 412 錯誤 – 先決條件失敗 (Precondition failed)介紹您的 Web 服務器認為,該服務器檢測到客戶端發送的 HTTP 數據流包括一個沒有滿足的‘先決條件’規范。HTTP 循環中的 412 錯誤任何客戶端 ( 例如您的瀏覽器或我們的 CheckUpDown 機器人 ) ,都需要…