MST

星途 面试题库

面试题:Java中条件变量与信号机制的基础应用

请简要描述在Java中如何使用条件变量(Condition)和信号机制(如通过Lock和Condition实现线程间通信)。假设你有一个生产者 - 消费者模型,用代码示例展示如何使用Condition实现线程间的协作,其中生产者线程向一个共享队列添加元素,消费者线程从队列中取出元素。
19.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. Condition概述

    • 在Java中,Condition是在java.util.concurrent.locks包下,配合Lock接口使用,用于实现更灵活的线程间通信。Condition可以实现类似传统ObjectwaitnotifynotifyAll方法的功能,但提供了更细粒度的控制。
    • Lock替代了synchronized关键字,Condition通过LocknewCondition()方法创建。
  2. 生产者 - 消费者模型代码示例

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

class ProducerConsumer {
    private final Queue<Integer> queue;
    private final int capacity;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();

    public ProducerConsumer(int capacity) {
        this.queue = new LinkedList<>();
        this.capacity = capacity;
    }

    public void produce(int item) throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == capacity) {
                notFull.await();
            }
            queue.add(item);
            System.out.println("Produced: " + item);
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public int consume() throws InterruptedException {
        lock.lock();
        try {
            while (queue.isEmpty()) {
                notEmpty.await();
            }
            int item = queue.poll();
            System.out.println("Consumed: " + item);
            notFull.signal();
            return item;
        } finally {
            lock.unlock();
        }
    }
}

class Producer implements Runnable {
    private final ProducerConsumer pc;
    private final int id;

    public Producer(ProducerConsumer pc, int id) {
        this.pc = pc;
        this.id = id;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                pc.produce(i * id);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

class Consumer implements Runnable {
    private final ProducerConsumer pc;
    private final int id;

    public Consumer(ProducerConsumer pc, int id) {
        this.pc = pc;
        this.id = id;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            try {
                pc.consume();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer(2);
        Thread producerThread1 = new Thread(new Producer(pc, 1));
        Thread producerThread2 = new Thread(new Producer(pc, 2));
        Thread consumerThread = new Thread(new Consumer(pc, 1));

        producerThread1.start();
        producerThread2.start();
        consumerThread.start();

        try {
            producerThread1.join();
            producerThread2.join();
            consumerThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在上述代码中:

  • ProducerConsumer类封装了共享队列和相关的LockCondition
  • produce方法中,当队列满时,生产者线程调用notFull.await()进入等待状态,当队列有空间时被唤醒并添加元素,然后调用notEmpty.signal()唤醒可能等待的消费者线程。
  • consume方法中,当队列为空时,消费者线程调用notEmpty.await()进入等待状态,当队列有元素时被唤醒并取出元素,然后调用notFull.signal()唤醒可能等待的生产者线程。
  • ProducerConsumer类分别实现了Runnable接口,用于模拟生产者和消费者线程的行为。
  • main方法中启动多个生产者和消费者线程来测试生产者 - 消费者模型。