Java多執行緒—執行緒同步(單訊號量互斥)

JayerListen發表於2022-05-03

JDK中Thread.State類的幾種狀態

執行緒的生命週期





執行緒的安全問題(同步與互斥)



方法一:同步程式碼塊

多個執行緒的同步監視器(鎖)必須的是同一把,任何一個類的物件都可以

      synchronized(同步監視器){
      
      }  //說明:操作共享資料的程式碼,即為需要被同步的程式碼(對共享資料的操作)

對於Thread實現和Runnable實現,同步鎖需要區別

1.Thread下的同同步鎖

class WinThread extends Thread{
/*
    方式一 繼承Thread
*/
    private static int ticket=100;  //需要設定靜態變數
    private static Object ticketLock=new Object(); //同步監視器,靜態,因為要是共享唯一變數
    @Override
    public void run() {
        while(true)
        {
            synchronized (ticketLock){
                if (ticket > 0)
                {
                    System.out.println(this.getName() + "賣票: " + ticket);
                    ticket--;
                }
                else break;
            }

        }
    }
}

2.Runnable下的同步鎖

class winRunnable implements Runnable{
    private int ticket=100; //不用設定成靜態變數
    private Object obj=new Object();    //宣告一個物件為鎖

    @Override
    public void run() {
        while(true)
        {
            try {
                sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized(obj){  //互斥操作
                if (ticket > 0)
                {
                    System.out.println(Thread.currentThread().getName() + "賣票: " + ticket);
                    ticket--;
                }
                else break;
            }
        }
    }
}

Thread下可以考慮用WinThread.class當鎖,而Runnable下可以考慮用this當鎖(總之要分析是不是同一個鎖)
自己的坑:不能把共享的資料當作鎖(例如WinThread下的int ticket改成Integer後當鎖),這裡還是會有問題


方法二:同步方法(程式碼略)

多宣告一個對共享資料資料操作的方法,在方法的前面新增宣告synchronized,而不是直接在run()前面加
1.同步方法中也涉及到同步鎖,但鎖是預設的
2.非靜態的同步方法,鎖是this
靜態的同步方法,鎖是當前類本身——xxx.class

 *              同步方法synchronized實現runnable介面
 *              private synchronized void 方法(){//普通同步方法的同步監視器是this
 *              //需要互斥的程式碼
 *          }
 *              同步方法synchronized實現繼承Thread類
 *                  因為不同執行緒是Thread類的不同物件,所以一般要用靜態
 *              private static synchronized void 方法(){//靜態同步方法預設同步監視器是類本身
 *                  //需要互斥的程式碼
 *              }

同步的侷限性:操作同步程式碼時,只能有一個執行緒參與,其他執行緒等待,相當於互斥量為1

單例模式的同步問題



死鎖問題



方法二:Lock(鎖) ---JDK5.0新增

class LockRunnable implements Runnable{
    private int ticket=100; //不用設定成靜態變數
    private ReentrantLock lock=new ReentrantLock(true); //true為選擇FIFO的公平
    @Override
    public void run() {
        while(true)
        {
            try {

                try {
                    sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                lock.lock();
                if (ticket > 0)
                {
                    System.out.println(Thread.currentThread().getName() + "賣票: " + ticket);
                    ticket--;
                }
                else break;
            }finally {
                lock.unlock();
            }
        }
    }
}

面試題:synchronized 與 Lock 的區別
相同:二者都可以解決執行緒安全問題
不同:synchronized機制在執行完相應的同步程式碼之後,自動的釋放同步監視器
Lock需要手動的啟動同步 .lock() ,同時結束同步也需要手動 .unlock()

相關文章