Java阻塞线程的概念及使用场景

在Java多线程编程中,阻塞线程是一种常见的情况。当线程遇到某些情况时,无法继续执行,会进入阻塞状态,直到满足特定条件才能继续执行。阻塞线程的使用场景包括等待输入、等待网络连接、等待锁、等待条件满足等。

1. 阻塞线程的原因

线程进入阻塞状态的原因有很多,包括但不限于:

  • 线程调用Thread.sleep(long millis)方法,主动进入睡眠状态,在指定的时间后恢复执行。
  • 线程调用wait()方法,让出对象锁,进入等待状态,直到被其它线程调用notify()notifyAll()方法唤醒。
  • 线程调用join()方法,等待另一个线程执行完毕后再继续执行。
  • 线程等待I/O操作完成,如读写文件、网络通信等。
  • 线程等待获取锁资源,如果锁已经被其它线程占用。

2. 使用示例

以一个简单的生产者-消费者模型为例,说明Java阻塞线程的使用。

import java.util.LinkedList;

class ProducerConsumer {
    private LinkedList<Integer> buffer = new LinkedList<>();
    private final int MAX_SIZE = 10;

    public void produce() throws InterruptedException {
        synchronized (this) {
            while (buffer.size() == MAX_SIZE) {
                // 缓冲区已满,生产者线程等待
                this.wait();
            }
            int value = 1; // 生产一个新值
            buffer.add(value);
            System.out.println("Produced: " + value);
            this.notifyAll(); // 唤醒等待的消费者线程
        }
    }

    public void consume() throws InterruptedException {
        synchronized (this) {
            while (buffer.isEmpty()) {
                // 缓冲区为空,消费者线程等待
                this.wait();
            }
            int value = buffer.removeFirst();
            System.out.println("Consumed: " + value);
            this.notifyAll(); // 唤醒等待的生产者线程
        }
    }
}

public class Main {
    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();

        Thread producerThread = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(1000); // 模拟生产耗时
                    pc.produce();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread consumerThread = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(2000); // 模拟消费耗时
                    pc.consume();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

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

在上述示例中,生产者线程和消费者线程共享一个缓冲区buffer,当缓冲区为空时,消费者线程进入阻塞状态等待生产者线程生产新的值。当缓冲区满时,生产者线程进入阻塞状态等待消费者线程消费值。在生产者和消费者之间通过synchronized实现互斥访问缓冲区,并使用wait()notifyAll()方法进行线程的阻塞和唤醒操作。

3. Java线程状态与阻塞线程的监控

在Java中,可以通过Thread.getState()方法来获取线程的状态。常见的线程状态包括NEWRUNNABLEBLOCKEDWAITINGTIMED_WAITINGTERMINATED

  • NEW:新创建的线程,还没有开始执行。
  • RUNNABLE:在Java虚拟机中执行的线程。
  • BLOCKED:被阻塞等待监视器锁定的线程。
  • WAITING:无限期地等待另一个线程执行特定操作的线程。
  • TIMED_WAITING:等待另一个线程执行操作,最多等待一段时间。