java.util.concurrent 之四:LinkedBlockingQueue

本文深入探讨了并发库中的阻塞队列,通过实例展示了如何使用阻塞队列进行线程间的数据交换,以及在多线程环境下实现同步与并发的基本原理。重点介绍了阻塞队列的主要方法put()和take(),并通过代码示例说明了它们的使用场景和效果。
并发库中的BlockingQueue是一个比较好玩的类,顾名思义,就是阻塞队列。该类主要提供了两个方法put()和take(),前者将一个对象放到队列尾部,如果队列已经满了,就等待直到有空闲节点;后者从head取一个对象,如果没有对象,就等待直到有可取的对象。
package test;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

public class MyBlockingQueue extends Thread{
public static BlockingQueue<String> queue=new LinkedBlockingQueue<String>(3);
private int index;
public MyBlockingQueue(int i){
this.index=i;
}

public void run(){
try{
queue.put(String.valueOf(this.index));
System.out.println("put {"+this.index+"} into queue!");
}catch(Exception e){
e.printStackTrace();
}
}

public static void main(String args[]){
ExecutorService service=Executors.newCachedThreadPool();
for( int i=0; i<10; i++){
service.submit(new MyBlockingQueue(i));
}
Thread thread = new Thread(){
public void run(){
try{
while(true){
Thread.sleep((int)(Math.random()*1000));
if(MyBlockingQueue.queue.isEmpty()) break;
String str=MyBlockingQueue.queue.take();
System.out.println("take {" + str+"} out of queue!");
}
}catch(Exception e){
e.printStackTrace();
}
}
};
service.submit(thread);
service.shutdown();
}

}

可能的运行结果:

put {0} into queue!
put {1} into queue!
put {3} into queue!
take {0} out of queue!
put {2} into queue!
take {1} out of queue!
put {7} into queue!
take {3} out of queue!
put {5} into queue!
take {2} out of queue!
put {4} into queue!
take {7} out of queue!
put {6} into queue!
put {9} into queue!
take {5} out of queue!
take {4} out of queue!
put {8} into queue!
take {6} out of queue!
take {9} out of queue!
take {8} out of queue!

### Java中ScheduledThreadPoolExecutor抛出RejectedExecutionException解决方案 #### 了解异常机制 `java.util.concurrent.RejectedExecutionException` 是Java并发编程中的常见异常,表明尝试向线程池提交的任务被拒绝。这种情况可能发生在线程池已满或正在关闭的情况下[^2]。 #### 原因分析 当 `ScheduledThreadPoolExecutor` 抛出 `RejectedExecutionException` 异常时,意味着任务提交失败。具体来说: - 线程池达到其配置的最大容量。 - 线程池正处于关闭过程中,不再接收新的任务请求。 - 队列满了而线程池不允许创建更多工作线程来处理积压的任务。 #### 处理策略 为了有效应对这一问题,可以采取以下几种措施之一或组合使用: ##### 调整线程池参数设置 通过调整线程池的核心大小、最大大小以及队列长度等参数,使得线程池能够更好地适应负载变化。例如增加核心线程数量或者允许更大的阻塞队列尺寸以容纳更多的待处理任务。 ```java // 创建具有更大灵活性的调度型线程池实例 ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingQueue<>(queueCapacity), threadFactory, handler); ``` ##### 设置合理的饱和政策 指定合适的拒绝策略处理器(handler),以便在线程池无法接纳新任务时按照预期行为响应。常用的有AbortPolicy(默认),CallerRunsPolicy,CipherDiscardOldestPolicy,DiscardPolicy种方式。 ```java // 使用自定义的手动运行调用者线程作为拒绝策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); ``` ##### 实施限流控制逻辑 引入流量控制系统,在应用程序层面限制单位时间内可提交给线程池的任务量,从而防止过载情况的发生。可以通过令牌桶算法或者其他形式实现速率限制功能。 ##### 定期监控与维护 定期检查并清理长时间未完成的任务,确保资源得到合理利用;同时也要关注系统性能指标的变化趋势,及时发现潜在风险点并作出相应优化调整。 #### 示例代码片段展示如何优雅地捕获和处理该类异常 ```java try { // 提交任务至线程池执行 Future<?> future = executor.submit(task); } catch (RejectedExecutionException e) { logger.error("Failed to submit task due to RejectedExecutionException", e); // 执行备用计划或其他补偿操作... } finally{ if (!executor.isShutdown()) { // 正确的方式去停止线程池而不是立即终止它 executor.shutdown(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值