下面是Java多线程阻塞与唤醒代码示例的完整攻略。
前置知识
在开始讲解Java多线程阻塞与唤醒代码示例之前,需要掌握以下知识点:
- 多线程的概念与基本操作,如创建线程、线程同步等;
- 线程阻塞与唤醒的概念与使用方法,如wait()、notify()、notifyAll()等;
- 线程状态的概念与使用,如Thread.State等。
示例一:生产者与消费者问题
生产者与消费者问题是一个非常经典的多线程问题,常用于考察多线程的基本操作、线程同步、线程阻塞与唤醒等知识点。下面给出一个生产者与消费者问题的代码示例:
public class ProducerConsumerExample {
private static final int BUFFER_SIZE = 10;
private static Queue<Integer> buffer = new LinkedList<>();
public static void main(String[] args) {
Thread producer = new ProducerThread();
Thread consumer = new ConsumerThread();
producer.start();
consumer.start();
}
private static class ProducerThread extends Thread {
@Override
public void run() {
int i = 0;
while (true) {
synchronized (buffer) {
if (buffer.size() < BUFFER_SIZE) {
buffer.offer(i++);
System.out.println("ProducerThread: Produced " + i);
buffer.notify();
} else {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
private static class ConsumerThread extends Thread {
@Override
public void run() {
while (true) {
synchronized (buffer) {
if (!buffer.isEmpty()) {
int value = buffer.poll();
System.out.println("ConsumerThread: Consumed " + value);
buffer.notify();
} else {
try {
buffer.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
上述代码实现了一个生产者与消费者协作的模型,生产者线程向一个固定长度的缓冲区中生产数字,消费者线程从缓冲区中取出数字并打印。其中,ProducerThread和ConsumerThread分别是生产者和消费者的线程类,buffer是一个缓冲区队列,BUFFER_SIZE是缓冲区队列的容量。线程协作的具体实现如下:
- 在生产者线程中,判断缓冲区队列是否已经满了,如果没有就生产一个数字插入队列,并调用buffer.notify()方法唤醒等待的消费者线程,否则就调用buffer.wait()方法进入等待状态。
- 在消费者线程中,判断缓冲区队列是否为空,如果不为空就取出一个数字打印,并调用buffer.notify()方法唤醒等待的生产者线程,否则就调用buffer.wait()方法进入等待状态。
通过上述代码示例,我们可以了解到Java多线程阻塞与唤醒的具体使用方法,并且实现了经典的生产者与消费者问题。
示例二:线程池的阻塞队列
线程池是一个非常常用的多线程技术,实现线程池需要使用到阻塞队列。下面给出一个线程池的阻塞队列的代码示例:
public class ThreadPoolWithBlockingQueueExample {
private static final int POOL_SIZE = 2;
private static final int TASK_NUM = 5;
private static final int QUEUE_SIZE = 3;
private static ExecutorService threadPool = new ThreadPoolExecutor(
POOL_SIZE,
POOL_SIZE,
0L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(QUEUE_SIZE),
new ThreadPoolExecutor.CallerRunsPolicy()
);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < TASK_NUM; i++) {
int taskId = i + 1;
threadPool.execute(() -> {
System.out.println("Task " + taskId + " is running on " + Thread.currentThread().getName());
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
threadPool.shutdown();
while (!threadPool.awaitTermination(100L, TimeUnit.MILLISECONDS)) {
System.out.println("Wait for thread pool termination");
}
System.out.println("Thread pool is terminated");
}
}
上述代码实现了一个线程池的阻塞队列模型,其中,ThreadPoolWithBlockingQueueExample是程序入口类,POOL_SIZE是线程池的核心线程数,TASK_NUM是任务的数量,QUEUE_SIZE是阻塞队列的大小,threadPool是线程池对象。线程协作的具体实现如下:
- 在main函数中,使用for循环向线程池中提交任务,每个任务都会打印一句话,并且线程会睡眠1s模拟任务执行时间。
- 在提交任务之后,调用threadPool.shutdown()方法关闭线程池,并且使用threadPool.awaitTermination()方法等待线程池中的线程执行完毕。
- 在等待线程池中的线程执行完毕的过程中,程序会不断打印"Wait for thread pool termination",直到线程池中的线程执行完毕,程序才会打印"Thread pool is terminated"。
通过上述代码示例,我们可以了解到线程池的阻塞队列是如何阻塞和唤醒线程的,以及如何正确地关闭线程池。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java多线程阻塞与唤醒代码示例 - Python技术站