1. 程式人生 > >javad多執行緒的顯示鎖和內建鎖

javad多執行緒的顯示鎖和內建鎖

一、內建鎖: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中,確保執行完時會釋放鎖
                }
            }
        }
    
    }