Java Wait用法

Java中的wait()方法是實現線程同步的重要手段之一,它可以讓線程等待其他線程的通知或者到達某個狀態再執行,有助於優化程序性能。本文將從多個角度詳細介紹Java Wait用法。

一、wait()方法的作用及基本用法

Java中的wait()方法可以讓一個線程等待另一個線程發出的通知或者到達某個狀態再執行,主要用於實現線程之間的同步和協作。因為Java中的線程是資源共享的,線程之間的訪問需要協調和同步,wait()方法就是一種實現線程同步的手段。

wait()方法的基本用法如下:

public synchronized void wait() throws InterruptedException

在synchronized方法中調用wait()方法時,當前線程進入等待狀態,直到其他線程調用notify()或者notifyAll()方法通知當前線程,或者等待時間耗盡才結束等待狀態。

wait()方法的示例代碼:

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " start waiting...");
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " end waiting...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + " notify...");
                lock.notify();
            }
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}

上述示例代碼中,thread1線程調用了wait()方法,進入等待狀態,直到thread2線程調用了notify()方法之後,才結束等待狀態。

二、wait()方法與notify()方法的配對使用

在使用wait()方法時,需要與notify()方法配對使用,notify()方法可以喚醒等待狀態的線程,讓它重新開始執行。

notify()方法的基本用法如下:

public final native void notify()

notify()方法的典型用法如下:

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " start waiting...");
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " end waiting...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + " notify...");
                lock.notify();
            }
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}

上述示例中,thread1線程調用了wait()方法進入等待狀態,直到thread2線程調用了notify()方法喚醒thread1線程,thread1線程才結束等待狀態並重新執行。

三、wait()方法和notify()方法的注意事項

1. wait()方法和notify()方法只能在synchronized代碼塊中使用

由於wait()方法和notify()方法需要對共享變數進行操作,因此只能在synchronized代碼塊中使用,否則會拋出IllegalMonitorStateException異常。

下面是一個使用wait()方法和notify()方法的非法示例:

public class ThreadTest {
    private static Object lock = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        Thread thread2 = new Thread(() -> {
            lock.notify();
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}

上述代碼中,wait()方法和notify()方法不在synchronized代碼塊中使用,因此會拋出IllegalMonitorStateException異常。

2. wait()方法必須放在循環中使用

在使用wait()方法時,為了避免虛假喚醒問題(即線程沒有收到notify()通知,但是等待結束了),wait()方法必須放在循環中使用,如下所示:

public class ThreadTest {
    private static Object lock = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                while (true) {
                    try {
                        System.out.println(Thread.currentThread().getName() + " start waiting...");
                        lock.wait();
                        System.out.println(Thread.currentThread().getName() + " end waiting...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + " notify...");
                lock.notify();
            }
        });
        thread1.start();
        Thread.sleep(1000);//等待線程1進入wait狀態
        thread2.start();
    }
}

上述代碼中,wait()方法放在while循環中使用,當線程被虛假喚醒時,會重新進入循環,直到收到notify()通知才結束等待狀態。

3. notify()方法不會釋放鎖

在調用notify()方法時,不會釋放鎖,因此在執行完notify()方法之後,線程仍然會保持鎖定狀態,在synchronized代碼塊中繼續執行。

下面是一個示例代碼:

public class ThreadTest {
    private static Object lock = new Object();
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " start waiting...");
                    lock.wait();
                    System.out.println(Thread.currentThread().getName() + " end waiting...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + " notify...");
                lock.notify();
                System.out.println(Thread.currentThread().getName() + " do something after notify...");
            }
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}

上述代碼中,當thread2線程調用notify()方法時,僅僅喚醒了thread1線程,而不會釋放鎖,因此thread2線程在執行完notify()方法之後,仍然在synchronized代碼塊中執行,直到執行完畢後才釋放鎖。

四、wait()方法的其他用法

除了基本用法外,wait()方法還可以通過指定等待時間或者超時時間,來控制等待狀態的結束,具體如下:

1. 指定等待時間

wait()方法可以指定等待時間,單位為毫秒,如果在指定時間內,其他線程沒有調用notify()方法通知當前線程,那麼當前線程會自動結束等待狀態,繼續向下執行。

wait()方法的用法如下:

public synchronized void wait(long timeout) throws InterruptedException
public final native void wait(long timeout, int nanos) throws InterruptedException

示例代碼如下:

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " start waiting for 2 seconds...");
                    lock.wait(2000);
                    System.out.println(Thread.currentThread().getName() + " end waiting...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + " notify...");
                lock.notify();
            }
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}

上述示例中,thread1線程調用了wait(2000)方法,等待2秒後自動結束等待狀態執行,即使此時還沒有收到notify()通知。

2. 超時時間

wait()方法還可以通過指定超時時間來控制等待狀態的結束,單位為納秒,如果在指定時間內,其他線程沒有調用notify()方法通知當前線程,那麼當前線程會自動結束等待狀態,繼續向下執行。

wait()方法的用法如下:

public final native void wait(long timeout, int nanos) throws InterruptedException

示例代碼如下:

public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Object lock = new Object();
        Thread thread1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println(Thread.currentThread().getName() + " start waiting...");
                    long start = System.nanoTime();
                    lock.wait(1000, 500);
                    long end = System.nanoTime();
                    System.out.println(Thread.currentThread().getName() + " end waiting..., elapsed time: " + (end - start) + "ns");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println(Thread.currentThread().getName() + " notify...");
                lock.notify();
            }
        });
        thread1.start();
        Thread.sleep(1000);
        thread2.start();
    }
}

上述示例中,thread1線程調用了wait(1000, 500)方法,等待1秒500納秒後自動結束等待狀態執行,即使此時還沒有收到notify()通知。

五、總結

本文從wait()方法的作用及基本用法、wait()方法與notify()方法的配對使用、wait()方法和notify()方法的注意事項、wait()方法的其他用法等多個方面對Java Wait用法做了詳細的闡述,並給出了相應的示例代碼,希望能夠幫助讀者深入理解Java Wait用法的實現原理和使用方法。

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

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
JMPC的頭像JMPC
上一篇 2024-10-04 00:24
下一篇 2024-10-04 00:24

相關推薦

  • Java JsonPath 效率優化指南

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

    編程 2025-04-29
  • java client.getacsresponse 編譯報錯解決方法

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

    編程 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
  • Java 8中某一周的周一

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

    編程 2025-04-29
  • Java判斷字元串是否存在多個

    本文將從以下幾個方面詳細闡述如何使用Java判斷一個字元串中是否存在多個指定字元: 一、字元串遍歷 字元串是Java編程中非常重要的一種數據類型。要判斷字元串中是否存在多個指定字元…

    編程 2025-04-29
  • VSCode為什麼無法運行Java

    解答:VSCode無法運行Java是因為默認情況下,VSCode並沒有集成Java運行環境,需要手動添加Java運行環境或安裝相關插件才能實現Java代碼的編寫、調試和運行。 一、…

    編程 2025-04-29
  • Java任務下發回滾系統的設計與實現

    本文將介紹一個Java任務下發回滾系統的設計與實現。該系統可以用於執行複雜的任務,包括可回滾的任務,及時恢復任務失敗前的狀態。系統使用Java語言進行開發,可以支持多種類型的任務。…

    編程 2025-04-29
  • Java 8 Group By 會影響排序嗎?

    是的,Java 8中的Group By會對排序產生影響。本文將從多個方面探討Group By對排序的影響。 一、Group By的概述 Group By是SQL中的一種常見操作,它…

    編程 2025-04-29

發表回復

登錄後才能評論