解決多執行緒併發問題
1、檔案鎖
如果對該表的更新或插入的操作,都會經過一個統一的檔案,這種方式是可以解決的多程序併發的問題;
實現方式如下:
public static function cbInventoryReserve() { $LOCK_FILE_PATH = $_SERVER['DOCUMENT_ROOT']."wmsinventoryapi/inventory/InventoryReserve.php"; $fp = fopen( $LOCK_FILE_PATH, "r" ); if (!$fp) { die("Failed to open the lock file!"); } flock ( $fp, LOCK_EX ); //需要進行的操作 $params = Flight::request()->getBody(); $params = json_decode($params, true); if (! is_array($params) || empty($params)) { Flight::sendRouteResult(array("error_code" => "40002","error_info" => "params empty")); } $result = \Inventory\InventoryEngine::getInstance()->inventoryReserve($params); flock ( $fp, LOCK_UN ); fclose ( $fp ); Flight::sendRouteResult($result); }
函式說明 flock()會依引數operation所指定的方式對引數fd所指的檔案做各種鎖定或解除鎖定的動作。此函式只能鎖定整個檔案,無法鎖定檔案的某一區域。
引數 operation有下列四種情況:
LOCK_SH 建立共享鎖定。多個程序可同時對同一個檔案作共享鎖定。
LOCK_EX 建立互斥鎖定。一個檔案同時只有一個互斥鎖定。
LOCK_UN 解除檔案鎖定狀態。
LOCK_NB 無法建立鎖定時,此操作可不被阻斷,馬上返回程序。通常與LOCK_SH或LOCK_EX 做OR(|)組合。
單一檔案無法同時建立共享鎖定和互斥鎖定,而當使用dup()或fork()時檔案描述詞不會繼承此種鎖定。
返回值 返回0表示成功,若有錯誤則返回-1,錯誤程式碼存於errno。
換言之:
使用共享鎖LOCK_SH,如果是讀取,不需要等待,但如果是寫入,需要等待讀取完成。
使用獨佔鎖LOCK_EX,無論寫入/讀取都需要等待。
LOCK_UN,無論使用共享/讀佔鎖,使用完後需要解鎖。
LOCK_NB,當被鎖定時,不阻塞,而是提示鎖定。
為了更好的移植性,對於檔案的開啟與關閉我選擇了fopen和fclose的組合,但flock的第一個引數要求的是int型別的檔案描述符。這裡對fopen返回的FILE型別的檔案指標進行轉換,轉換為int型的檔案描述符 (假設open函式返回的檔案描述符為fd,而fopen返回的檔案指標為*fp,則fd等價於fp->_fileno).
2、序列化介面(物件序列化)
所有php裡面的值都可以使用函式serialize()來返回一個包含位元組流的字串來表示。unserialize()函式能夠重新把字串變回php原來的值。 序列化一個物件將會儲存物件的所有變數,但是不會儲存物件的方法,只會儲存類的名字。
<?php // classa.inc: class A { public $one = 1; public function show_one() { echo $this->one; } } // page1.php: include("classa.inc"); $a = new A; $s = serialize($a); // 把變數$s儲存起來以便檔案page2.php能夠讀到 file_put_contents('store', $s); // page2.php: // 要正確瞭解序列化,必須包含下面一個檔案 include("classa.inc"); $s = file_get_contents('store'); $a = unserialize($s); // 現在可以使用物件$a裡面的函式 show_one() $a->show_one(); ?>
3、select *** for update
Select …forupdate語句是我們經常使用手工加鎖語句。通常情況下,select語句是不會對資料加鎖,妨礙影響其他的DML和DDL操作。同時,在多版本一致讀機制的支援下,select語句也不會被其他型別語句所阻礙。
藉助for update子句,我們可以在應用程式的層面手工實現資料加鎖保護操作。
for update子句的預設行為就是自動啟動一個事務,藉助事務的鎖機制將資料進行鎖定。
開啟一個事務使用for update
start transaction; select sum(quantity) from ws_inventory_item where inventory_item_id=86 for update;
再開啟另一個事務時,做update 操作的時,只能等待上面的事務,commit才能執行;
start transaction; update ws_inventory_item set quantity = quantity + 1 where inventory_item_id = 86;MySQL 使用 SELECT … FOR UPDATE 做事務寫入前的確認 以MySQL 的InnoDB 為例,預設的 Tansaction isolation level 為 REPEATABLE READ,在 SELECT 的讀取鎖定主要分為兩種方式:
SELECT … LOCK IN SHARE MODE SELECT … FOR UPDATE這兩種方式在事務(Transaction) 進行當中SELECT 到同一個資料表時,都必須等待其它事務資料被提交(Commit)後才會執行。而主要的不同在於LOCK IN SHARE MODE 在有一方事務要Update 同一個表單時很容易造成死鎖 。 簡單的說,如果SELECT 後面若要UPDATE 同一個表單,最好使用 SELECT … UPDATE。 舉個例子:假設商品表單products 內有一個存放商品數量的quantity ,在訂單成立之前必須先確定quantity 商品數量是否足夠(quantity>0) ,然後才把數量更新為1。 不安全的做法:
SELECT quantity FROM products WHERE id=3; UPDATE products SET quantity = 1 WHERE id=3;為什麼不安全呢? 少量的狀況下或許不會有問題,但是大量的資料存取「鐵定」會出問題。 如果我們需要在 quantity>0 的情況下才能扣庫存,假設程式在第一行 SELECT 讀到的 quantity 是 2 ,看起來數字沒有錯,但是當MySQL 正準備要UPDATE 的時候,可能已經有人把庫存扣成 0 了,但是程式卻渾然不知,將錯就錯的 UPDATE 下去了。 因此必須透過的事務機制來確保讀取及提交的資料都是正確的。 於是我們在MySQL 就可以這樣測試:(注1)
1 SET AUTOCOMMIT=0; 2 BEGIN WORK; 3 SELECT quantity FROM products WHERE id=3 FOR UPDATE;此時 products 資料中 id=3 的資料被鎖住(注3),其它事務必須等待此次事務提交後才能執行 SELECT * FROM products WHERE id=3 FOR UPDATE (注2)如此可以確保 quantity 在別的事務讀到的數字是正確的。
1 UPDATE products SET quantity = '1' WHERE id=3 ; 2 COMMIT WORK;提交(Commit)寫入資料庫,products 解鎖。 注1:BEGIN/COMMIT 為事務的起始及結束點,可使用二個以上的MySQL Command 視窗來互動觀察鎖定的狀況。 注2:在事務進行當中,只有SELECT … FOR UPDATE 或LOCK IN SHARE MODE 同一筆資料時會等待其它事務結束後才執行,一般SELECT … 則不受此影響。 注3:由於InnoDB 預設為Row-level Lock,資料列的鎖定可參考這篇。 注4:InnoDB 表單儘量不要使用LOCK TABLES 指令,若情非得已要使用,請先看官方對於InnoDB 使用LOCK TABLES 的說明,以免造成系統經常發生死鎖。 MySQL SELECT … FOR UPDATE 的 Row Lock 與 Table Lock 上面介紹過SELECT … FOR UPDATE 的用法,不過鎖定(Lock)的資料是判別就得要注意一下了。由於InnoDB 預設是Row-Level Lock,所以只有「明確」地指定主鍵,MySQL 才會執行 Row lock (只鎖住被選取的資料) ,否則MySQL 將會執行 Table Lock (將整個資料表單給鎖住)。 舉個例子: 假設有個表單products ,裡面有id 跟name 二個欄位,id 是主鍵。 例1: (明確指定主鍵,並且有此資料,row lock)
SELECT * FROM products WHERE id='3' FOR UPDATE;例2: (明確指定主鍵,若查無此資料,無lock)
SELECT * FROM products WHERE id='-1' FOR UPDATE;例2: (無主鍵,table lock)
SELECT * FROM products WHERE name='Mouse' FOR UPDATE;例3: (主鍵不明確,table lock)
SELECT * FROM products WHERE id<>'3' FOR UPDATE;例4: (主鍵不明確,table lock)
SELECT * FROM products WHERE id LIKE '3' FOR UPDATE;注1: FOR UPDATE 僅適用於InnoDB,且必須在事務區塊(BEGIN/COMMIT)中才能生效。 注2: 要測試鎖定的狀況,可以利用MySQL 的Command Mode ,開二個視窗來做測試。
4、事務隔離級別
如何解決多程序或多執行緒併發問題
本節轉載,原文地址:http://singo107.iteye.com/blog/1175084
資料庫事務的隔離級別有4個,由低到高依次為Read uncommitted、Read committed、Repeatable read、Serializable,這四個級別可以逐個解決髒讀、不可重複讀、幻讀這幾類問題。
√: 可能出現 ×: 不會出現
髒讀 | 不可重複讀 | 幻讀 | |
Read uncommitted | √ | √ | √ |
Read committed | × | √ | √ |
Repeatable read | × | × | √ |
Serializable | × | × | × |
注意:我們討論隔離級別的場景,主要是在多個事務併發的情況下,因此,接下來的講解都圍繞事務併發。
Read uncommitted 讀未提交
公司發工資了,領導把5000元打到singo的賬號上,但是該事務並未提交,而singo正好去檢視賬戶,發現工資已經到賬,是5000元整,非常高興。可是不幸的是,領導發現發給singo的工資金額不對,是2000元,於是迅速回滾了事務,修改金額後,將事務提交,最後singo實際的工資只有2000元,singo空歡喜一場。
出現上述情況,即我們所說的髒讀,兩個併發的事務,“事務A:領導給singo發工資”、“事務B:singo查詢工資賬戶”,事務B讀取了事務A尚未提交的資料。
當隔離級別設定為Read uncommitted時,就可能出現髒讀,如何避免髒讀,請看下一個隔離級別。
Read committed 讀提交
singo拿著工資卡去消費,系統讀取到卡里確實有2000元,而此時她的老婆也正好在網上轉賬,把singo工資卡的2000元轉到另一賬戶,並在singo之前提交了事務,當singo扣款時,系統檢查到singo的工資卡已經沒有錢,扣款失敗,singo十分納悶,明明卡里有錢,為何......
出現上述情況,即我們所說的不可重複讀,兩個併發的事務,“事務A:singo消費”、“事務B:singo的老婆網上轉賬”,事務A事先讀取了資料,事務B緊接了更新了資料,並提交了事務,而事務A再次讀取該資料時,資料已經發生了改變。
當隔離級別設定為Read committed時,避免了髒讀,但是可能會造成不可重複讀。
大多數資料庫的預設級別就是Read committed,比如Sql Server , Oracle。如何解決不可重複讀這一問題,請看下一個隔離級別。
Repeatable read 重複讀
當隔離級別設定為Repeatable read時,可以避免不可重複讀。當singo拿著工資卡去消費時,一旦系統開始讀取工資卡資訊(即事務開始),singo的老婆就不可能對該記錄進行修改,也就是singo的老婆不能在此時轉賬。
雖然Repeatable read避免了不可重複讀,但還有可能出現幻讀。
singo的老婆工作在銀行部門,她時常通過銀行內部系統檢視singo的信用卡消費記錄。有一天,她正在查詢到singo當月信用卡的總消費金額(select sum(amount) from transaction where month = 本月)為80元,而singo此時正好在外面胡吃海塞後在收銀臺買單,消費1000元,即新增了一條1000元的消費記錄(insert transaction ... ),並提交了事務,隨後singo的老婆將singo當月信用卡消費的明細列印到A4紙上,卻發現消費總額為1080元,singo的老婆很詫異,以為出現了幻覺,幻讀就這樣產生了。
注:Mysql的預設隔離級別就是Repeatable read。
Serializable 序列化
Serializable是最高的事務隔離級別,同時代價也花費最高,效能很低,一般很少使用,在該級別下,事務順序執行,不僅可以避免髒讀、不可重複讀,還避免了幻像讀。
Mysql事務隔離級別設定方式
使用者可以用SET TRANSACTION語句改變單個會話或者所有新進連線的隔離級別。它的語法如下:
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
注意:預設的行為(不帶session和global)是為下一個(未開始)事務設定隔離級別。如果你使用GLOBAL關鍵字,語句在全域性對從那點開始建立的所有新連線(除了不存在的連線)設定預設事務級別。你需要SUPER許可權來做這個。使用SESSION 關鍵字為將來在當前連線上執行的事務設定預設事務級別。 任何客戶端都能自由改變會話隔離級別(甚至在事務的中間),或者為下一個事務設定隔離級別。
Java 多執行緒併發程式設計會有許多不同的問題,主要有如下問題的應用:
- 多執行緒讀寫共享資料同步問題
- 併發讀資料,保持各個執行緒讀取到的資料一致性的問題。
解決方案:
- synchronized關鍵字和Lock併發鎖:主要解決多執行緒共享資料同步問題。
- ThreadLocal主要解決多執行緒中資料因併發產生不一致問題。
ThreadLocal與synchronized有本質的區別:
synchronized是利用鎖的機制,使變數或程式碼塊在某一時該只能被一個執行緒訪問。 而ThreadLocal為每一個執行緒都提供了變數的副本,使得每個執行緒在某一時間訪問到的並不是同一個物件,這樣就隔離了多個執行緒對資料的資料共享。 ThreadLocal與synchronized有本質的區別: synchronized是利用鎖的機制,使變數或程式碼塊在某一時該只能被一個執行緒訪問。而ThreadLocal為每一個執行緒都提供了變數的副本,使得每個執行緒在某一時間訪問到的並不是同一個物件,這樣就隔離了多個執行緒對資料的資料共享。而Synchronized卻正好相反,它用於在多個執行緒間通訊時能夠獲得資料共享。ThreadLocal與synchronized有本質的區別: synchronized是利用鎖的機制,使變數或程式碼塊在某一時該只能被一個執行緒訪問。而ThreadLocal為每一個執行緒都提供了變數的副本,使得每個執行緒在某一時間訪問到的並不是同一個物件,這樣就隔離了多個執行緒對資料的資料共享。而Synchronized卻正好相反,它用於在多個執行緒間通訊時能夠獲得資料共享。
ThreadLocal是什麼?
早在JDK 1.2的版本中就提供Java.lang.ThreadLocal,ThreadLocal為解決多執行緒程式的併發問題提供了一種新的思路。使用這個工具類可以很簡潔地編寫出優美的多執行緒程式。
ThreadLocal很容易讓人望文生義,想當然地認為是一個“本地執行緒”。其實,ThreadLocal並不是一個Thread,而是Thread的區域性變數,也許把它命名為ThreadLocalVariable更容易讓人理解一些。
當使用ThreadLocal維護變數時,ThreadLocal為每個使用該變數的執行緒提供獨立的變數副本,所以每一個執行緒都可以獨立地改變自己的副本,而不會影響其它執行緒所對應的副本。
從執行緒的角度看,目標變數就象是執行緒的本地變數,這也是類名中“Local”所要表達的意思。
執行緒區域性變數並不是Java的新發明,很多語言(如IBM IBM XL FORTRAN)在語法層面就提供執行緒區域性變數。在Java中沒有提供在語言級支援,而是變相地通過ThreadLocal的類提供支援。
所以,在Java中編寫執行緒區域性變數的程式碼相對來說要笨拙一些,因此造成執行緒區域性變數沒有在Java開發者中得到很好的普及。
ThreadLocal的介面方法
ThreadLocal類介面很簡單,只有4個方法,我們先來了解一下:
void set(Object value)
設定當前執行緒的執行緒區域性變數的值。
public Object get()
該方法返回當前執行緒所對應的執行緒區域性變數。
public void remove()
將當前執行緒區域性變數的值刪除,目的是為了減少記憶體的佔用,該方法是JDK 5.0新增的方法。需要指出的是,當執行緒結束後,對應該執行緒的區域性變數將自動被垃圾回收,所以顯式呼叫該方法清除執行緒的區域性變數並不是必須的操作,但它可以加快記憶體回收的速度。
protected Object initialValue()
返回該執行緒區域性變數的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲呼叫方法,線上程第1次呼叫get()或set(Object)時才執行,並且僅執行1次。ThreadLocal中的預設實現直接返回一個null。
值得一提的是,在JDK5.0中,ThreadLocal已經支援泛型,該類的類名已經變為ThreadLocal<T>。API方法也相應進行了調整,新版本的API方法分別是void set(T value)、T get()以及T initialValue()。
ThreadLocal是如何做到為每一個執行緒維護變數的副本的呢?其實實現的思路很簡單:在ThreadLocal類中有一個Map,用於儲存每一個執行緒的變數副本,Map中元素的鍵為執行緒物件,而值對應執行緒的變數副本。我們自己就可以提供一個簡單的實現版本:
- <span style="font-size:18px;">// 程式碼清單1 SimpleThreadLocal
- class SimpleThreadLocal {
- private Map valueMap = Collections.synchronizedMap(new HashMap());
- public void set(Object newValue) {
- valueMap.put(Thread.currentThread(), newValue);// ①鍵為執行緒物件,值為本執行緒的變數副本
- }
- public Object get() {
- Thread currentThread = Thread.currentThread();
- Object o = valueMap.get(currentThread);// ②返回本執行緒對應的變數
- if (o == null && !valueMap.containsKey(currentThread)) {// ③如果在Map中不存在,放到Map
- // 中儲存起來。
- o = initialValue();
- valueMap.put(currentThread, o);
- }
- return o;
- }
- public void remove() {
- valueMap.remove(Thread.currentThread());
- }
- public Object initialValue() {
- return null;
- }
- }</span>
雖然程式碼清單9?3這個ThreadLocal實現版本顯得比較幼稚,但它和JDK所提供的ThreadLocal類在實現思路上是相近的。
一個TheadLocal例項
- <span style="font-size:18px;">package threadLocalDemo;
- public class SequenceNumber {
- // ①通過匿名內部類覆蓋ThreadLocal的initialValue()方法,指定初始值
- private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
- public Integer initialValue() {
- return 0;
- }
- };
- // ②獲取下一個序列值
- public int getNextNum() {
- seqNum.set(seqNum.get() + 1);
- return seqNum.get();
- }
- public static void main(String[] args)
- {
- SequenceNumber sn = new SequenceNumber();
- // ③ 3個執行緒共享sn,各自產生序列號
- TestClient t1 = new TestClient(sn);
- TestClient t2 = new TestClient(sn);
- TestClient t3 = new TestClient(sn);
- t1.start();
- t2.start();
- t3.start();
- }
- private static class TestClient extends Thread
- {
- private SequenceNumber sn;
- public TestClient(SequenceNumber sn) {
- this.sn = sn;
- }
- public void run()
- {
- for (int i = 0; i < 3; i++) {
- // ④每個執行緒打出3個序列值
- System.out.println("thread[" + Thread.currentThread().getName()+"] sn[" + sn.getNextNum() + "]");
- }
- }
- }
- }</span>
參考文獻:
- http://www.xuebuyuan.com/1628079.html
- http://blog.sina.com.cn/s/blog_5204918b0100d044.html
相關推薦
【小家Java】Future、FutureTask、CompletionService、CompletableFuture解決多執行緒併發中歸集問題的效率對比
相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9
解決多執行緒併發問題
1、檔案鎖 如果對該表的更新或插入的操作,都會經過一個統一的檔案,這種方式是可以解決的多程序併發的問題; 實現方式如下: public static function cbInventoryReserve() { $LOCK_FILE_PATH = $_S
關於android解決多執行緒併發的問題
1.建立HandlerThread物件和Handler物件,併為HandlerThread生成的執行緒命名, private HandlerThread thread=new HandlerThread("handlerthread"); //建立的HandlerThrea
7. 多執行緒併發相關問題和解決技巧
一. 如何使用多執行緒 實際案例 https://intrinio.com/tutorial/web_api 我們通過上述網站提供的API獲取了股市資訊的CSV資料, 現在要下載大量CSV資料檔案, 並將其轉化為xml檔案 如何使用執行緒來提高下載並處理的效率? 解決方案
多執行緒併發問題解決之redis鎖
一 問題背景 我們做的是醫療資訊化系統,在系統中一條患者資訊對醫院中當前科室中的所有診斷醫生是可見的,當有一個診斷醫生點選按鈕處理該資料時,資料的狀態發生了變化,其他的醫生就不可以再處理此患者的資料了。我們開始的做法是,在醫生點選按鈕時先去後臺數據庫獲
Spring-利用ThreadLocal解決執行緒安全問題(多執行緒併發登入)
ThreadLocal是什麼ThreadLocal,顧名思義,它不是一個執行緒,而是執行緒的一個本地化物件。當工作於多執行緒中的物件使用ThreadLocal維護變數時,ThreadLocal為每個使用該變數的執行緒分配一個獨立的變數副本。所以每一個執行緒都可以獨立地改變自己
解決多執行緒程式設計中大併發數等待喚醒的問題
在移動交通流調查專案的一個演算法分析程式中,碰到一個業務問題:使用者採集上傳的基站定位資料需要進行分析預處理,方案是先按預定格式解析檔案並從中提取出成百上千個基站定位資料記錄,併合並相同的基站點,根據獲取到的基站位置資訊作為引數,去請求google 基站
自己在之前做兩個專案中遇到多執行緒併發訪問如何解決的一個簡單demo程式
package com.geloin.main; public class TestMoreThread { public static void main(String[] args) { final test t0=new test(); final te
實現Runnable解決多執行緒資料安全問題
xl_echo編輯整理,歡迎轉載,轉載請宣告文章來源。更多IT、程式設計案例、資料請聯絡QQ:1280023003,加群298140694。百戰不敗,依不自稱常勝,百敗不頹,依能奮力前行。——這才是真正的堪稱強大!! 之前的文章我們講到了,四個電影院視窗同時出售50張彩票的
面試題之——多執行緒併發面試題
1) 什麼是執行緒? 執行緒是作業系統能夠進行運算排程的最小單位,它被包含在程序之中,是程序中的實際運作單位。程式設計師可以通過它進行多處理器程式設計,你可以使用多執行緒對運算密集型任務提速。比如,如果一個執行緒完成一個任務要100毫秒,那麼用十個執行緒完成改任務只需10毫秒。Java在語言層面對多執行
網際網路架構多執行緒併發程式設計高階教程(上)
#基礎篇幅:執行緒基礎知識、併發安全性、JDK鎖相關知識、執行緒間的通訊機制、JDK提供的原子類、併發容器、執行緒池相關知識點 #高階篇幅:ReentrantLock原始碼分析、對比兩者原始碼,更加深入理解讀寫鎖,JAVA記憶體模型、先行發生原則、指令重排序 #環境說明:idea、ja
實驗5 結果不唯一的多執行緒併發執行例項 操作指導
實驗5 結果不唯一的多執行緒併發執行例項 操作指導 變數及函式說明 pthread_t 型別定義:typedef unsigned long int pthread_t; //come from /usr/include/bits/
JAVA學習筆記(併發程式設計 - 玖)- 多執行緒併發拓展
文章目錄 死鎖 概念 產生條件 例子 併發最佳實踐 Spring與執行緒安全 死鎖 概念 死鎖是指兩個或兩個以上的程序在執行過程中,由於競爭資源或者由於彼此通訊而造成的一種阻塞的現象
Jmeter測試多執行緒併發請求 與 OSS 物件儲存 測試報告
1.測試資料夾包含特殊字元 出現重大BUG問題: \\ 和 / 運用到Key中 資料夾不能刪除 解決方案:應該在根源上傳之前進行 規避 出現這樣的字元在一起 直接丟擲錯誤資訊給使用者 2.測
鎖機制——解決多執行緒的資料共享帶來的同步問題
“非執行緒安全”——多個執行緒對同一個物件中的例項變數進行併發訪問時發生,產生的後果就是“髒讀”,也就是取到的資料其實是被更改過的。 1、方法內的變數為執行緒安全的 方法內部的私有變數,則不存在“非執行緒安全”的問題,所得結果也就是“執行緒安全”的。 2、例項變數非執行緒安全 如果多個執行緒
Java多執行緒-併發之執行緒池
執行緒池有了解嗎? 答: java.util.concurrent.ThreadPoolExecutor 類就是一個執行緒池。客戶端呼叫ThreadPoolExecutor.submit(Runnable task) 提交任務,執行緒池內部維護的工作者執行緒的數量就是該執行緒池的執行
Java多執行緒-併發之synchronized 關鍵字
synchronized 關鍵字 答: 底層實現: 進入時,執行 monitorenter,將計數器 +1,釋放鎖 monitorexit 時,計數器 -1 當一個執行緒判斷到計數器為 0 時,則當前鎖空閒,可以佔用;反之,當前執行緒進入等待狀態 含義
Java多執行緒-併發之sleep() 和 wait(n) 、 wait() 的區別
sleep() 和 wait(n) 、 wait() 的區別 答: sleep 方法:是 Thread 類的靜態方法,當前執行緒將睡眠 n 毫秒,執行緒進入阻塞狀態。當睡眠時間到了,會接觸阻塞,進入可執行狀態,等待 CPU 的到來。睡眠不釋放鎖(如果有的話) wai
Java多執行緒-併發之多執行緒產生死鎖的4個必要條件?如何避免死鎖?
多執行緒產生死鎖的4個必要條件? 答: 互斥條件:一個資源每次只能被一個執行緒使用 請求與保持條件:一個執行緒因請求資源而阻塞時,對已獲得的資源保持不放 不剝奪條件:程序已經獲得的資源,在未使用完之前,不能強行剝奪 迴圈等待條件:若干執行緒之間形成一種頭
Java多執行緒-併發之執行緒和程序的區別
執行緒和程序的區別 答: 程序是一個“執行中的程式”,是系統進行資源分配和排程的一個獨立單位 執行緒是程序的一個實體,一個程序中擁有多個執行緒,執行緒之間共享地址空間和其他資源(所以通訊和同步等操作執行緒比程序更加容易) 執行緒上下文的切換比程序上下文切換要快