等待队列和执行队列
在Java中,等待队列和执行队列是非常常见的概念。它们在多线程编程中起着重要的作用,用于协调线程的执行顺序和相互之间的通信。
等待队列
等待队列是指一个存储等待线程的数据结构,用于在特定条件满足之前暂停线程的执行。当一个线程调用某个对象的wait()
方法时,它会被放入等待队列中,直到其他线程调用相同对象的notify()
或notifyAll()
方法将其唤醒。
等待队列的主要作用是提供一种线程间通信的机制,使得线程能够等待某个条件的发生,从而避免了线程的忙等待,提高了线程的效率。
在Java中,等待队列通常与synchronized
关键字一起使用,如下所示的示例代码:
public class WaitQueueExample {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread producerThread = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("Producer is waiting...");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Producer is resumed.");
}
});
Thread consumerThread = new Thread(() -> {
synchronized (lock) {
System.out.println("Consumer is notifying...");
lock.notify();
}
});
producerThread.start();
consumerThread.start();
}
}
在上述代码中,producerThread
线程调用了lock.wait()
方法,将自己放入了等待队列中。而consumerThread
线程调用了lock.notify()
方法,唤醒了等待队列中的线程。
执行队列
执行队列是指一个存储等待执行任务的数据结构,用于按照一定的顺序和策略执行任务。通常情况下,执行队列是由线程池来管理的,它通过维护一个线程池和一个任务队列来实现任务的执行。
线程池在Java中的实现是ExecutorService
接口及其实现类ThreadPoolExecutor
。当一个任务被提交到线程池时,如果线程池中有空闲线程,任务就会立即被执行;如果线程池中没有空闲线程,任务则会被放入任务队列中,等待空闲线程的出现。
下面是一个使用ThreadPoolExecutor
的示例代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorServiceExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
for (int i = 0; i < 5; i++) {
final int taskId = i;
executorService.submit(() -> {
System.out.println("Task " + taskId + " is running.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task " + taskId + " is finished.");
});
}
executorService.shutdown();
}
}
在上述代码中,我们创建了一个固定大小为2的线程池,然后提交了5个任务。由于线程池的大小为2,所以只能同时执行两个任务,剩下的任务会被放入任务队列中,等待线程空闲。
总结
等待队列和执行队列是多线程编程中常用的概念。等待队列用于暂停线程的执行,直到某个条件满足;执行队列用于按照一定顺序和策略执行任务。通过合理地使用等待队列和执行队列,我们可以实现线程间的协作,提高多线程程序的效率和可靠性。