Java並發編程之wait方法使用

Java中的wait方法是多線程中常用的一種同步方式,它的作用是讓線程進入等待狀態,直到其他線程調用notify或者notifyAll方法喚醒它。在控制線程同步方面,wait方法的使用是非常必要的。

一、wait方法基本用法

wait方法用於等待其他線程的通知,並且會釋放鎖資源。下面是wait方法的基本用法:

try {
    synchronized (this) {
        wait();
    }
} catch (InterruptedException e) {
    e.printStackTrace();
}

在上述代碼中,首先獲取對象鎖,然後調用wait方法使當前線程進入等待狀態,直到其他線程調用notify或者notifyAll方法喚醒它。當線程進入等待狀態後,所佔用的鎖資源會被釋放出來,其他線程就可以獲取這個鎖。

在wait方法上,也可以設置等待的最大時間,如果在等待時間內沒有被喚醒,線程就會自動蘇醒。具體的代碼如下:

try {
    synchronized (this) {
        wait(1000);
    }
} catch (InterruptedException e) {
    e.printStackTrace();
}

在上述代碼中,等待時間為1000毫秒,如果在此時間內沒有被喚醒,線程就會自動蘇醒。

二、notify和notifyAll方法

notify方法用於喚醒一個等待中的線程,而notifyAll方法用於喚醒所有等待中的線程。

以下是notify和notifyAll方法的用法示例:

try {
    synchronized (this) {
        notify();
        // 或者notifyAll();
    }
} catch (Exception e) {
    e.printStackTrace();
}

三、wait和notify的經典應用場景

1. 生產者和消費者問題

生產者和消費者問題是多線程中常見的一種同步問題。生產者和消費者共同使用一個隊列,生產者向隊列中生產數據,消費者從隊列中取出數據。如果隊列已經滿了,生產者就需要等待消費者取走數據以後才能繼續生產,如果隊列已經空了,消費者就需要等待生產者生產數據以後才能繼續消費。

下面是使用wait和notify來解決生產者和消費者問題的經典實現:

import java.util.LinkedList;
import java.util.Queue;

public class ProducerConsumer {
    private final Queue<Object> queue = new LinkedList<>();
    private final int MAX_SIZE = 10;

    public void produce(Object obj) throws InterruptedException {
        synchronized (queue) {
            while (queue.size() == MAX_SIZE) {
                System.out.println("隊列已滿,生產者等待...");
                queue.wait();//隊列已滿,等待消費者消費
            }
            queue.add(obj);//生產一個元素
            System.out.println("生產者生產了一個元素,隊列中元素個數:" + queue.size());
            queue.notifyAll();//喚醒所有消費者線程
        }
    }

    public void consume() throws InterruptedException {
        synchronized (queue) {
            while (queue.isEmpty()) {
                System.out.println("隊列為空,消費者等待...");
                queue.wait(); //隊列為空,等待生產者生產
            }
            Object obj = queue.poll();//消費一個元素
            System.out.println("消費者消費了一個元素,隊列中元素個數:" + queue.size());
            queue.notifyAll();//喚醒所有生產者線程
        }
    }
}

2. 等待-通知機制的使用

在多線程中,基於等待-通知機制來進行協作,是實現同步的重要方式之一。下面是一個使用等待-通知機制來協作的實例:

public class WaitNotifyDemo {
    private static volatile boolean flag = false;
    private static final Object obj = new Object();

    public static void main(String[] args) {
        Thread waitThread = new Thread(new WaitTask(), "WaitThread");
        waitThread.start();
        SleepUtils.second(1);
        Thread notifyThread = new Thread(new NotifyTask(), "NotifyThread");
        notifyThread.start();
    }

    static class WaitTask implements Runnable {
        public void run() {
            synchronized (obj) {
                while (!flag) {
                    System.out.println(Thread.currentThread() + " flag is false. wait...");
                    try {
                        obj.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread() + " flag is true. running...");
            }
        }
    }

    static class NotifyTask implements Runnable {
        public void run() {
            synchronized (obj) {
                System.out.println(Thread.currentThread() + " hold lock. notify...");
                obj.notifyAll();
                flag = true;//將flag設置為true
                SleepUtils.second(5);
            }
            synchronized (obj) {
                System.out.println(Thread.currentThread() + " hold lock again. sleep...");
                SleepUtils.second(5);
            }
        }
    }
}

四、總結

wait和notify是Java中多線程同步的重要工具,在進行線程調度和任務協作時非常重要。使用wait和notify需要注意以下幾點:

  1. wait和notify方法必須在同步塊中調用。
  2. 在調用wait方法的時候,需要首先獲取對象鎖,否則會拋出IllegalMonitorStateException異常。
  3. 在調用wait方法時,線程會自動釋放鎖,進入等待狀態,等待其他線程的通知。
  4. 在調用notify方法時,也需要首先獲取對象鎖,否則會拋出IllegalMonitorStateException異常。
  5. 在調用notify方法後,會喚醒一個處於等待狀態的線程,並使其進入就緒狀態。
  6. wait方法還可以設置等待的最大時間,如果在此時間內沒有被喚醒,則線程會自動蘇醒。

原創文章,作者:OODK,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/148231.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
OODK的頭像OODK
上一篇 2024-11-03 15:14
下一篇 2024-11-03 15:15

相關推薦

  • java client.getacsresponse 編譯報錯解決方法

    java client.getacsresponse 編譯報錯是Java編程過程中常見的錯誤,常見的原因是代碼的語法錯誤、類庫依賴問題和編譯環境的配置問題。下面將從多個方面進行分析…

    編程 2025-04-29
  • Java JsonPath 效率優化指南

    本篇文章將深入探討Java JsonPath的效率問題,並提供一些優化方案。 一、JsonPath 簡介 JsonPath是一個可用於從JSON數據中獲取信息的庫。它提供了一種DS…

    編程 2025-04-29
  • Java Bean加載過程

    Java Bean加載過程涉及到類加載器、反射機制和Java虛擬機的執行過程。在本文中,將從這三個方面詳細闡述Java Bean加載的過程。 一、類加載器 類加載器是Java虛擬機…

    編程 2025-04-29
  • Java騰訊雲音視頻對接

    本文旨在從多個方面詳細闡述Java騰訊雲音視頻對接,提供完整的代碼示例。 一、騰訊雲音視頻介紹 騰訊雲音視頻服務(Cloud Tencent Real-Time Communica…

    編程 2025-04-29
  • Java Milvus SearchParam withoutFields用法介紹

    本文將詳細介紹Java Milvus SearchParam withoutFields的相關知識和用法。 一、什麼是Java Milvus SearchParam without…

    編程 2025-04-29
  • ArcGIS更改標註位置為中心的方法

    本篇文章將從多個方面詳細闡述如何在ArcGIS中更改標註位置為中心。讓我們一步步來看。 一、禁止標註智能調整 在ArcMap中設置標註智能調整可以自動將標註位置調整到最佳顯示位置。…

    編程 2025-04-29
  • 解決.net 6.0運行閃退的方法

    如果你正在使用.net 6.0開發應用程序,可能會遇到程序閃退的情況。這篇文章將從多個方面為你解決這個問題。 一、代碼問題 代碼問題是導致.net 6.0程序閃退的主要原因之一。首…

    編程 2025-04-29
  • Python創建分配內存的方法

    在python中,我們常常需要創建並分配內存來存儲數據。不同的類型和數據結構可能需要不同的方法來分配內存。本文將從多個方面介紹Python創建分配內存的方法,包括列表、元組、字典、…

    編程 2025-04-29
  • Python中init方法的作用及使用方法

    Python中的init方法是一個類的構造函數,在創建對象時被調用。在本篇文章中,我們將從多個方面詳細討論init方法的作用,使用方法以及注意點。 一、定義init方法 在Pyth…

    編程 2025-04-29
  • Java 8中某一周的周一

    Java 8是Java語言中的一個版本,於2014年3月18日發布。本文將從多個方面對Java 8中某一周的周一進行詳細的闡述。 一、數組處理 Java 8新特性之一是Stream…

    編程 2025-04-29

發表回復

登錄後才能評論