Java中的執行緒通訊詳解

省赚客开发者团队發表於2024-07-13

Java中的執行緒通訊詳解

大家好,我是微賺淘客系統3.0的小編,是個冬天不穿秋褲,天冷也要風度的程式猿!

在多執行緒程式設計中,執行緒之間的通訊是一個重要且複雜的主題。為了確保多執行緒程式的正確性和效率,執行緒需要能夠互相通訊並協調工作。Java 提供了多種方式來實現執行緒間的通訊,如 wait()notify()notifyAll() 方法,以及更高階的併發工具類。本文將詳細介紹 Java 中的執行緒通訊,涵蓋基本概念、常用方法和具體程式碼示例。

一、基本概念

執行緒通訊是指執行緒之間透過某種機制傳遞資訊,以協調它們之間的行為。Java 中提供了內建的執行緒通訊機制,包括 wait()notify()notifyAll() 方法,這些方法都是 Object 類的一部分,每個物件都可以作為執行緒通訊的鎖。

二、wait()notify()notifyAll()方法

  1. wait()方法

wait() 方法使當前執行緒進入等待狀態,直到其他執行緒呼叫 notify()notifyAll() 方法喚醒它。該方法必須在同步塊或同步方法中呼叫,否則會丟擲 IllegalMonitorStateException 異常。

  1. notify()方法

notify() 方法喚醒一個正在等待該物件監視器的執行緒。如果有多個執行緒在等待,則選擇其中一個執行緒喚醒。被喚醒的執行緒在獲取物件的監視器後,才能繼續執行。

  1. notifyAll()方法

notifyAll() 方法喚醒所有正在等待該物件監視器的執行緒。被喚醒的執行緒在獲取物件的監視器後,才能繼續執行。

三、程式碼示例

以下示例演示瞭如何使用 wait()notify()notifyAll() 方法進行執行緒通訊。

1. 生產者-消費者模型

package cn.juwatech.threads;

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

public class ProducerConsumerExample {
    private static final int CAPACITY = 5;
    private final Queue<Integer> queue = new LinkedList<>();
    private final Object lock = new Object();

    public static void main(String[] args) {
        ProducerConsumerExample example = new ProducerConsumerExample();
        Thread producerThread = new Thread(example.new Producer());
        Thread consumerThread = new Thread(example.new Consumer());

        producerThread.start();
        consumerThread.start();
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            int value = 0;
            while (true) {
                synchronized (lock) {
                    while (queue.size() == CAPACITY) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    queue.offer(value);
                    System.out.println("Produced: " + value);
                    value++;
                    lock.notify();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            while (true) {
                synchronized (lock) {
                    while (queue.isEmpty()) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    }
                    int value = queue.poll();
                    System.out.println("Consumed: " + value);
                    lock.notify();
                }
            }
        }
    }
}

在這個示例中,生產者執行緒生成整數並將其放入佇列中,而消費者執行緒從佇列中取出整數並進行消費。wait()notify() 方法用於協調生產者和消費者之間的工作。

四、使用更高階的併發工具類

Java 提供了更高階的併發工具類,如 BlockingQueueSemaphoreCountDownLatchCyclicBarrier,它們簡化了執行緒間的通訊和同步。

1. 使用 BlockingQueue 實現生產者-消費者模型

package cn.juwatech.threads;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class BlockingQueueExample {
    private static final int CAPACITY = 5;
    private final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(CAPACITY);

    public static void main(String[] args) {
        BlockingQueueExample example = new BlockingQueueExample();
        Thread producerThread = new Thread(example.new Producer());
        Thread consumerThread = new Thread(example.new Consumer());

        producerThread.start();
        consumerThread.start();
    }

    class Producer implements Runnable {
        @Override
        public void run() {
            int value = 0;
            while (true) {
                try {
                    queue.put(value);
                    System.out.println("Produced: " + value);
                    value++;
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    class Consumer implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    int value = queue.take();
                    System.out.println("Consumed: " + value);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }
}

在這個示例中,BlockingQueue 處理了同步和通訊邏輯,使得程式碼更加簡潔和易於理解。

2. 使用 Semaphore 控制執行緒訪問

Semaphore 是一種計數訊號量,用於控制同時訪問特定資源的執行緒數量。

package cn.juwatech.threads;

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private static final int PERMITS = 3;
    private final Semaphore semaphore = new Semaphore(PERMITS);

    public static void main(String[] args) {
        SemaphoreExample example = new SemaphoreExample();
        for (int i = 0; i < 10; i++) {
            new Thread(example.new Worker(i)).start();
        }
    }

    class Worker implements Runnable {
        private final int workerId;

        Worker(int workerId) {
            this.workerId = workerId;
        }

        @Override
        public void run() {
            try {
                semaphore.acquire();
                System.out.println("Worker " + workerId + " is working...");
                Thread.sleep(2000);
                System.out.println("Worker " + workerId + " finished working.");
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                semaphore.release();
            }
        }
    }
}

在這個示例中,Semaphore 控制同時最多隻有三個執行緒可以訪問資源,其餘執行緒必須等待。

五、執行緒通訊的最佳實踐

  1. 避免忙等待:使用 wait()notify()notifyAll() 或併發工具類避免忙等待,提高效率。
  2. 適當使用鎖和同步:確保共享資源的安全訪問,避免死鎖。
  3. 選擇合適的併發工具類:根據具體需求選擇合適的併發工具類,簡化執行緒通訊和同步邏輯。

透過以上內容,我們詳細介紹了 Java 中的執行緒通訊機制,包括基本概念、常用方法及其具體程式碼示例,並探討了使用更高階的併發工具類實現執行緒通訊的方法。掌握這些知識,能夠幫助我們編寫出更加高效和可靠的多執行緒程式。

著作權歸聚娃科技微賺淘客系統開發者團隊,轉載請註明出處!

相關文章