Java: 线程通信

简介

在多线程编程中,线程通信是指多个线程之间通过共享的变量或者特定的方法来实现数据的交换和协作。线程通信使得多个线程能够有序地执行任务,避免了资源竞争和数据不一致的问题。Java提供了一些机制来实现线程通信,包括wait()/notify()/notifyAll()方法和Lock/Condition接口等。

wait()/notify()/notifyAll()方法

在Java中,每个对象都有一个内部锁(也称为监视器锁),可以通过synchronized关键字来获取。wait()/notify()/notifyAll()方法是Object类中定义的用于线程通信的方法,只能在同步代码块或同步方法中调用。

  • wait(): 使当前线程进入等待状态,释放对象锁,直到其他线程调用该对象的notify()或notifyAll()方法来唤醒。
  • notify(): 唤醒一个正在等待该对象锁的线程,使其从等待状态转变为可运行状态。如果有多个线程在等待,只会随机选择一个线程进行唤醒。
  • notifyAll(): 唤醒所有正在等待该对象锁的线程,使它们从等待状态转变为可运行状态。

下面是一个简单的示例代码,演示了如何使用wait()/notify()方法实现线程通信:

class Message {
    private String content;
    private boolean isReady = false;

    public synchronized void setContent(String content) {
        while (isReady) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.content = content;
        isReady = true;
        notify();
    }

    public synchronized String getContent() {
        while (!isReady) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        isReady = false;
        notify();
        return content;
    }
}

class Producer implements Runnable {
    private Message message;

    public Producer(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        String[] messages = {"Hello", "World", "Java"};
        for (String msg : messages) {
            message.setContent(msg);
            System.out.println("Produced: " + msg);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        message.setContent("Done");
    }
}

class Consumer implements Runnable {
    private Message message;

    public Consumer(Message message) {
        this.message = message;
    }

    @Override
    public void run() {
        while (true) {
            String content = message.getContent();
            System.out.println("Consumed: " + content);
            if ("Done".equals(content)) {
                break;
            }
        }
    }
}

public class ThreadCommunicationExample {
    public static void main(String[] args) {
        Message message = new Message();
        Thread producerThread = new Thread(new Producer(message));
        Thread consumerThread = new Thread(new Consumer(message));
        producerThread.start();
        consumerThread.start();
    }
}

在上面的示例中,有两个线程,一个生产者线程和一个消费者线程。生产者线程通过调用setContent()方法设置消息内容,并调用notify()方法唤醒消费者线程。消费者线程则通过调用getContent()方法获取消息内容,并调用wait()方法等待生产者线程的唤醒。

Lock/Condition接口

除了使用wait()/notify()/notifyAll()方法外,Java还提供了Lock/Condition接口来实现线程通信。Lock接口是Java并发包中的一部分,它提供了比synchronized关键字更加灵活和强大的锁定机制。Condition接口是Lock接口的一部分,它可以通过await()/signal()/signalAll()方法来实现线程的等待和唤醒。

下面是一个使用Lock/Condition接口实现线程通信的示例代码:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Message {
    private String content;
    private boolean isReady = false;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void setContent(String content) {
        lock.lock();
        try {
            while (isReady) {
                try {
                    condition.await();
                } catch (InterruptedException e