多線程使用之-----synchronized/wait/notify/yeid

參考文獻: java synchronized詳解

  • synchronized 修飾方法
public synchronized void accessVal(int newVal);  

synchronized 方法控制對類成員變量的訪問:每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執(zhí)行,否則所屬線程阻塞,方法一旦執(zhí)行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此后被阻塞的線程方能獲得該鎖,重新進入可執(zhí)行狀態(tài)。這種機制確保了同一時刻對于每一個類實例,其所有聲明為 synchronized 的成員函數(shù)中至多只有一個處于可執(zhí)行狀態(tài)(因為至多只有一個能夠獲得該類實例對應的鎖),從而有效避免了類成員變量的訪問沖突(只要所有可能訪問類成員變量的方法均被聲明為 synchronized)。 在 Java 中,不光是類實例,每一個類也對應一把鎖,這樣我們也可將類的靜態(tài)成員函數(shù)聲明為 synchronized ,以控制其對類的靜態(tài)成員變量的訪問。

  • 修飾代碼塊
 synchronized (object) {
            waitThread.start();
            try {
                System.out.print("主線程等待\n");
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

獲得的鎖是傳入的 類的實例中的鎖
有如下一個例子:

public class Main {

   private static  dog  object = new dog();

    public static void main(String[] args) {

        System.out.print("主線程運行\(zhòng)n");
        WaitThread waitThread = new WaitThread();

         //waitThread.start();  

        synchronized (object) {
            waitThread.start();  //注意此處放的地方
            try {
                System.out.print("主線程等待\n");
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.print("主線程結束\n");
    }

    static class WaitThread extends  Thread {
        @Override
        public void run() {
            try {
                synchronized (object) {
                    Thread.sleep(3000);
                    System.out.print("主線程喚起\n");
                    object.notifyAll();
                }
            } catch (Exception e) {

            }
        }
    }
}

結果:

主線程運行
主線程等待
(sleep3秒)
主線程喚起
主線程結束
Process finished with exit code 0

請注意上述例子中的waitThread.start(); 執(zhí)行的地方,是放在了synchronized(Objedt) {} 塊中;如果將此代碼放到它的外邊也就是注釋掉的地方,就會有問題:

主線程運行
(sleep3秒)
主線程喚起
主線程等待

因為在執(zhí)行 run方法時已經(jīng)持有了object 的鎖,主線程中的synchronized 的實例object鎖 已經(jīng)被持有了,所以不能執(zhí)行,等子線程中的鎖釋放之后主線程才可以執(zhí)行

注意點:wait() , notify() ,notifyAll() ,必須放在synchronized block 中,否則會拋異常。也就是說它們都是線程不安全的。

在做測試的時候每次wait()之后的nofity()時線程在爭奪同一把鎖的時候是隨機的,誰搶到就給誰。
notifyAll() 讓我想起了在做驅動時的一種驚群效應,一旦鎖被釋放了,所有的wait線程被喚醒。

對于對象obj來說:
obj.wait():該方法的調用,使得調用該方法的執(zhí)行線程(T1)放棄obj的對象鎖并阻塞,直到別的線程調用了obj的notifyAll方法、或者別的線程調用了obj的notify方法且JVM選擇喚醒(T1),被喚醒的線程(T1)依舊阻塞在wait方法中,與其它的線程一起爭奪obj的對象鎖,直到它再次獲得了obj的對象鎖之后,才能從wait方法中返回。(除了notify方法,wait還有帶有時間參數(shù)的版本,在等待了超過所設時間之后,T1線程一樣會被喚醒,進入到爭奪obj對象鎖的行列;另外中斷可以直接跳出wait方法)

obj.notify():該方法的調用,會從所有正在等待obj對象鎖的線程中,喚醒其中的一個(選擇算法依賴于不同實現(xiàn)),被喚醒的線程此時加入到了obj對象鎖的爭奪之中,然而該notify方法的執(zhí)行線程此時并未釋放obj的對象鎖,而是離開synchronized代碼塊時釋放。因此在notify方法之后,synchronized代碼塊結束之前,所有其他被喚醒的,等待obj對象鎖的線程依舊被阻塞。

obj.notifyAll():與notify的區(qū)別是,該方法會喚醒所有正在等待obj對象鎖的線程。(不過同一時刻,也只有一個線程可以擁有obj的對象鎖)

另Thread.join() : 阻塞當前調用join函數(shù)時所在的線程,直到接受線程執(zhí)行完畢之后再繼續(xù),有點類似wait,但是這個是Thread調用,阻塞當前調用線程的,并直到執(zhí)行的線程執(zhí)行完畢之后才不阻塞當前線程

Thread.yeid() :使該函數(shù)的線程讓出CPU固定的時間。主動讓出線程的執(zhí)行權給其他線程。因為讓的的線程有可能被線程調度程序再次選中,所以有可能沒有效果(親測確實如此),謹慎使用。

public static void main(String[] args) {


        Mrunable1 thread1 = new Mrunable1("A\n");
        Mrunable1 thread2 = new Mrunable1("B\n");

        thread1.start();
        thread2.start();

    }

    static class Mrunable1 extends Thread {
        public Mrunable1(String name) {
            super(name);
        }

        @Override
        public synchronized void run() {
            while (true) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.print(Thread.currentThread().getName());

                Thread.yield();
            }
        }
這是其中的部分截圖
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽閱讀 2,591評論 1 15
  • Java多線程學習 [-] 一擴展javalangThread類 二實現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,105評論 1 18
  • 該文章轉自:http://blog.csdn.net/evankaka/article/details/44153...
    加來依藍閱讀 7,464評論 3 87
  • 寫在前面的話: 這篇博客是我從這里“轉載”的,為什么轉載兩個字加“”呢?因為這絕不是簡單的復制粘貼,我花了五六個小...
    SmartSean閱讀 4,935評論 12 45
  • 再上層的心法前提需要扎實的基本功,一個人能夠舉重若輕,在于基本功扎實? 可是,怎么練基本功?扎實的標準又是什么?什...
    泊明者矣閱讀 332評論 0 0

友情鏈接更多精彩內(nèi)容