javad多執行緒的顯示鎖和內建鎖
阿新 • • 發佈:2018-12-22
一、內建鎖:Synchronized
1、內建鎖的獲得鎖和釋放鎖是隱式的,進入synchrnozied修飾的程式碼要獲得鎖,走出相應的程式碼要釋放鎖。
2、與synchronized配套使用的執行緒通訊方式:wait() 、notify() 、notifyAll()
wait會立刻釋放當前鎖,並進入等待狀態,等待的到相應的notify重新獲得鎖後才繼續執行。
notify不會立刻釋放鎖,而是等到notify所在synchronized程式碼塊全部都執行完以後才會釋放鎖。
notifyAll會通知等待佇列中的所有執行緒。
3、內建鎖,在進入同步程式碼塊時,採取的時無限等待的策略,一旦開始等待,就既不能中斷也不能取消,容易產生飢餓和死鎖問題。
二、顯示鎖:ReentrantLock
1、需要顯示進行lock和unlock操作
2、RenntrantLock實現了Lock介面,並提供了與Synchronized相同的互斥性和記憶體可見性。
Lock lock=new ReentrantLock();
上鎖: lock.lock();
釋放鎖:lock.unlock(); (最好放在finally塊中,確保能執行)
3、同步鎖Lock也有對應的執行緒通訊機制:Condition
Condition c=lock.newCondition();
等待: c.await()
喚醒:c.signal() 和 c.signalAll()
注意:無論是內建鎖還是顯示鎖,建立多個執行緒時都應該確保所使用的鎖物件都應該是同一個。
注意:為了避免 虛假喚醒 的問題,wait應該儘可能放在while迴圈判斷中
public static void main(String[] args){ Ticket t=new Ticket(); //只建立一個物件,確保三個執行緒所使用的是同一把鎖 new Thread(t,"一號視窗").start(); new Thread(t,"二號視窗").start(); new Thread(t,"三號視窗").start(); } class Ticket implements Runnable{ Lock lock=new ReentrantLock(); public int tickets=100; public void run(){ while(true){ try { Thread.sleep(100); lock.lock(); //上鎖 if (tickets > 0) System.out.println(Thread.currentThread().getName() + "完成售票,剩餘票數:" + --tickets); else return; }catch(Exception e){ } finally { lock.unlock(); //放在finally中,確保執行完時會釋放鎖 } } } }