线程池中有哪些常见的阻塞队列?
时间: 2023-08-24 12:11:22 浏览: 148
在 Java 中,线程池中常见的阻塞队列有以下几种:
1. ArrayBlockingQueue:一个基于数组实现的有界阻塞队列。它按照先进先出(FIFO)的顺序对元素进行排序。
2. LinkedBlockingQueue:一个基于链表实现的可选有界或无界阻塞队列。当队列为空时,获取操作将会被阻塞。
3. SynchronousQueue:一个没有容量的阻塞队列。每个插入操作必须等待另一个线程的移除操作,反之亦然。
4. PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。元素按照它们的自然顺序或者通过构造方法提供的 Comparator 进行排序。
这些阻塞队列在线程池中用于存储待执行的任务。不同的阻塞队列选择适合的场景可以提供更好的性能和线程调度策略。例如,ArrayBlockingQueue 在有限的线程池中可以提供更好的控制和限制,而 LinkedBlockingQueue 在可扩展性和高并发场景下更适合使用。
相关问题
自定义线程池怎样设置线程池的阻塞队列
### 配置BlockingQueue作为任务队列
在Java中自定义线程池时,`ThreadPoolExecutor`允许指定不同的阻塞队列来管理待处理的任务。以下是几种常见的阻塞队列及其适用场景:
#### 使用ArrayBlockingQueue
当希望设定一个固定容量的任务队列时可以选择`ArrayBlockingQueue`。这种类型的队列为有界队列,适合于需要严格控制最大并发量的应用程序。
```java
import java.util.concurrent.*;
public class CustomThreadPool {
private final ThreadPoolExecutor executor;
public CustomThreadPool() {
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10);
this.executor = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60L, TimeUnit.SECONDS,
workQueue
);
}
}
```
#### 使用LinkedBlockingQueue
对于那些预期会有大量短期任务到来但是又不想让它们占用过多内存的情况来说,`LinkedBlockingQueue`是一个不错的选择。如果不指定期望的最大长度,默认情况下它是无界的,这可能会带来潜在的风险如OutOfMemoryError。
```java
import java.util.concurrent.*;
public class CustomThreadPoolWithUnboundedQueue {
private final ThreadPoolExecutor executor;
public CustomThreadPoolWithUnboundedQueue() {
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>();
this.executor = new ThreadPoolExecutor(
2, // 核心线程数
Integer.MAX_VALUE, // 实际应用应避免如此高的上限
60L, TimeUnit.SECONDS,
workQueue
);
}
}
```
#### 使用SynchronousQueue
如果应用程序中的任务几乎总是立即被某个工作线程取走执行而无需排队等待,则可考虑采用`SynchronousQueue`。这类队列实际上并不保存任何元素;每次插入都必须有一个对应的移除操作同时发生。
```java
import java.util.concurrent.*;
public class DirectHandoffThreadPool {
private final ThreadPoolExecutor executor;
public DirectHandoffThreadPool() {
BlockingQueue<Runnable> workQueue = new SynchronousQueue<>();
this.executor = new ThreadPoolExecutor(
0, // 不保留核心线程
Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
workQueue
);
}
}
```
#### 使用PriorityBlockingQueue
为了使某些高优先级的任务能够得到更早的调度机会,可以利用实现了`Comparator`接口的对象配合`PriorityBlockingQueue`一起使用。需要注意的是,由于这是一个无界的延迟队列,因此同样要注意防止内存泄漏问题[^3]。
```java
import java.util.concurrent.*;
import java.util.Comparator;
import org.example.MyTask; // 假设MyTask实现了Comparable<MyTask>
public class PriorityBasedThreadPool {
private final ThreadPoolExecutor executor;
public PriorityBasedThreadPool() {
Comparator<MyTask> comparator = (o1, o2) -> /* 定义比较逻辑 */;
BlockingQueue<Runnable> workQueue = new PriorityBlockingQueue<>(11, comparator);
this.executor = new ThreadPoolExecutor(
2, // 核心线程数
4, // 最大线程数
60L, TimeUnit.SECONDS,
workQueue
);
}
}
线程池拒绝策略加入到阻塞队列
你可以通过将自定义的拒绝策略添加到线程池的阻塞队列中来实现。在Java中,线程池的阻塞队列通常使用`BlockingQueue`接口的实现类。下面是一种常见的做法:
1. 创建一个实现了`RejectedExecutionHandler`接口的自定义拒绝策略类,例如`CustomRejectedExecutionHandler`。
2. 在自定义拒绝策略类中,重写`rejectedExecution`方法,该方法会在任务被线程池拒绝执行时被调用。在该方法中,你可以根据需求对被拒绝的任务进行处理,例如将其添加到阻塞队列中。
3. 创建一个线程池,使用`ThreadPoolExecutor`类。在创建线程池时,可以指定阻塞队列的实现类,并将自定义的拒绝策略对象作为参数传递给线程池构造函数。
以下是一个示例代码:
```java
import java.util.concurrent.*;
public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
private final BlockingQueue<Runnable> queue;
public CustomRejectedExecutionHandler(BlockingQueue<Runnable> queue) {
this.queue = queue;
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
queue.put(r); // 将被拒绝的任务添加到阻塞队列中
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
public class Main {
public static void main(String[] args) {
int corePoolSize = 5;
int maximumPoolSize = 10;
long keepAliveTime = 5000;
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);
RejectedExecutionHandler rejectionHandler = new CustomRejectedExecutionHandler(queue);
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
TimeUnit.MILLISECONDS,
queue,
rejectionHandler
);
// 使用线程池执行任务
threadPool.execute(() -> {
// 任务逻辑
});
}
}
```
在上面的示例中,自定义拒绝策略类`CustomRejectedExecutionHandler`将被拒绝的任务添加到阻塞队列中。然后,创建一个`ThreadPoolExecutor`线程池,并将阻塞队列和自定义的拒绝策略对象传递给构造函数。
这样,当线程池无法接受新任务时,会调用自定义的拒绝策略,并将被拒绝的任务添加到阻塞队列中。这个阻塞队列将会在有空闲线程时被持续消费执行。
阅读全文
相关推荐















