问一下关于ThreadPoolExecutor中得阻塞队列问题

JSP_killmylife 2020-05-28 12:03:08
话不多说,先上代码:
public class BIOTest {
public static void main(String[] args) throws IOException {
ExecutorService eService= new ThreadPoolExecutor(
1,
Runtime.getRuntime().availableProcessors(),
5,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
ServerSocket sSocket=new ServerSocket(9527);
System.out.println("服务开始");

while(true) {
//监听
final Socket socket=sSocket.accept();
System.out.println("有人进来了");

eService.execute(()->{
handler(socket);
});
}


}

public static void handler(Socket socket) {

try {
// System.out.println("当前线程为:"+Thread.currentThread().getName());
byte[] bytes=new byte[1024];
InputStream inp =socket.getInputStream();
while(true) {
int read = inp.read(bytes);
if(read!=-1) {
System.out.println(Thread.currentThread().getName()+":"+new String(bytes,0,read));
}else {break;}
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}finally {
System.out.println(Thread.currentThread().getName()+" OUT");
try {
socket.close();
} catch (Exception e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
}
}

现在得问题是,当我使用Linked/ArrayBlockingQueue的时候,使用命令telnet 127.0.0.1 9527一直都只有一条线程,两个窗口运行这个命令会形成阻塞,必须关闭第一个窗口使得第二个窗口发送得信息得以发送给服务端,但使用SynchronousQueue就没有这个问题,为什么呢?
...全文
768 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_45897252 2020-06-03
  • 打赏
  • 举报
回复
引用 4 楼 一个帅逼 的回复:
线程池执行顺序 核心线程->等待队列->最大线程 ,你核心线程数就1,而且用的是LinkedBlockingQueue,当然只有一个线程能正常操作,另外一个线程任务都被存在队列中了,并不会开启新线程去执行,而SynchronousQueue这个队列其实是特殊的阻塞队列,它内部实际不会存储任务,你可以去看看SynchronousQueue的特点
欧猴
RAIN5920 2020-05-31
  • 打赏
  • 举报
回复
11111111111111
一个帅逼 2020-05-29
  • 打赏
  • 举报
回复
引用 9 楼 JSP_killmylife 的回复:
[quote=引用 8 楼 一个帅逼 的回复:] [quote=引用 5 楼 JSP_killmylife 的回复:] [quote=引用 4 楼 一个帅逼 的回复:] 线程池执行顺序 核心线程->等待队列->最大线程 ,你核心线程数就1,而且用的是LinkedBlockingQueue,当然只有一个线程能正常操作,另外一个线程任务都被存在队列中了,并不会开启新线程去执行,而SynchronousQueue这个队列其实是特殊的阻塞队列,它内部实际不会存储任务,你可以去看看SynchronousQueue的特点
这个我知道,我专门看了帖子才来发问的,帖子是这个:https://blog.csdn.net/qq_26881739/article/details/80983495 我只是很疑惑,稍微配合一下靠近业务的代码就这个效果,之前看的时候就是for循环执行线程池是没有这个问题的[/quote]那你疑惑什么,你的问题是什么,你发的帖子看了下,就是简单的介绍了下三种队列,你可以试着把你的表述弄的简洁一点[/quote] 我的我的,想都没想就提问了,我只想知道为什么只有一条核心线程工作,明明指认了最大核心线程[/quote]所以我前面就说了java线程池的执行顺序,你核心线程数就是1,等待队列长度3,你开两个线程,那显然只会有一个线程在执行,另外一个线程被存入队列中,只要你的核心线程不结束,它就会一直阻塞住,最大线程数的一个使用前提是等待队列满了才会创建新线程去执行。
JSP_killmylife 2020-05-28
  • 打赏
  • 举报
回复
我去,怎么修改了我原本得意思,不是中断吧,是第二个窗口发送得消息无法在控制台输出,必须关闭第一个窗口,第二个窗口发送得信息才得以输出,最主要是不知道为什么线程只有一条但使用SynchronousQueue就没有这个问题
一个帅逼 2020-05-28
  • 打赏
  • 举报
回复
线程池执行顺序 核心线程->等待队列->最大线程 ,你核心线程数就1,而且用的是LinkedBlockingQueue,当然只有一个线程能正常操作,另外一个线程任务都被存在队列中了,并不会开启新线程去执行,而SynchronousQueue这个队列其实是特殊的阻塞队列,它内部实际不会存储任务,你可以去看看SynchronousQueue的特点
  • 打赏
  • 举报
回复
世上没有奇怪的问题,只有没有研究透的问题。 把线程池核心线程数改大试试。
小码人生 2020-05-28
  • 打赏
  • 举报
回复
释放资源问题吧。SynchronousQueue这个应该会自动释放资源,其他需要手动释放吧
JSP_killmylife 2020-05-28
  • 打赏
  • 举报
回复
引用 11 楼 ITjavaman 的回复:
针对你一楼说的问题,我是这么认为的 当执行的任务超过核心线程数corePoolSize,超出的任务会放到队列里,当超出的任务超过队列长度时,最大线程数maximumPoolSize这个参数开始起作用,超出的任务线程池会启动新的线程去执行这些任务(这些新创建的线程数量不超过maximumPoolSize-corePoolSize) 你代码使用LinkedBlockingQueue,核心线程数为1,队列长度为3 当你添加第二个任务的时候(也就是连接第二个窗口的时候),第二个任务被放进队列等待消费(知道第一个任务被消费) 重点来了,你使用了SynchronousQueue这个队列,这个队列是没有长度的, 也就是说添加第二个任务的时候,maximumPoolSize开始生效(也就是线程池会新增线程去执行第二个任务) 备注 (1)使用LinkedBlockingQueue,你把长度设置为1,然后开3个窗口去连接 (2)使用SynchronousQueue,maximumPoolSize设置为1,然后开2个窗口去连接 按备注操作一下分析一下估计就明白我说啥了
明白了,感谢大佬,我本该去看源码的,麻烦你们了!
ITjavaman 2020-05-28
  • 打赏
  • 举报
回复
针对你一楼说的问题,我是这么认为的 当执行的任务超过核心线程数corePoolSize,超出的任务会放到队列里,当超出的任务超过队列长度时,最大线程数maximumPoolSize这个参数开始起作用,超出的任务线程池会启动新的线程去执行这些任务(这些新创建的线程数量不超过maximumPoolSize-corePoolSize) 你代码使用LinkedBlockingQueue,核心线程数为1,队列长度为3 当你添加第二个任务的时候(也就是连接第二个窗口的时候),第二个任务被放进队列等待消费(知道第一个任务被消费) 重点来了,你使用了SynchronousQueue这个队列,这个队列是没有长度的, 也就是说添加第二个任务的时候,maximumPoolSize开始生效(也就是线程池会新增线程去执行第二个任务) 备注 (1)使用LinkedBlockingQueue,你把长度设置为1,然后开3个窗口去连接 (2)使用SynchronousQueue,maximumPoolSize设置为1,然后开2个窗口去连接 按备注操作一下分析一下估计就明白我说啥了
JSP_killmylife 2020-05-28
  • 打赏
  • 举报
回复
引用 7 楼 qingyuan18 的回复:
你的线程池容量只有1,用SynchronousQueue,两个窗口除非是完全同一时间片在发消息,否则肯定是一个线程先消费完SynchronousQueue队列然后退出了,然后第二个窗口再用池里面的线程再消费SynchronousQueue队列,当然不会阻塞,我不相信你如果是同一时间戳在发消息,用SynchronousQueue还可以并行 你可以写一个客户端来模拟,sleep下让线程不要马上退出,再试试SynchronousQueue 另外你想实现什么业务场景呢? 如果想精确的线程逻辑并且控制并发粒度,建议你用concurrent包下的各种锁,而不要依靠ExecutorThread里面的队列容器
意思是其他队列不会主动释放资源所以会阻塞是吧?其实也没有相关的业务场景,就是想练一练,java并发包还是模模糊糊的,待会试一下
JSP_killmylife 2020-05-28
  • 打赏
  • 举报
回复
引用 8 楼 一个帅逼 的回复:
[quote=引用 5 楼 JSP_killmylife 的回复:] [quote=引用 4 楼 一个帅逼 的回复:] 线程池执行顺序 核心线程->等待队列->最大线程 ,你核心线程数就1,而且用的是LinkedBlockingQueue,当然只有一个线程能正常操作,另外一个线程任务都被存在队列中了,并不会开启新线程去执行,而SynchronousQueue这个队列其实是特殊的阻塞队列,它内部实际不会存储任务,你可以去看看SynchronousQueue的特点
这个我知道,我专门看了帖子才来发问的,帖子是这个:https://blog.csdn.net/qq_26881739/article/details/80983495 我只是很疑惑,稍微配合一下靠近业务的代码就这个效果,之前看的时候就是for循环执行线程池是没有这个问题的[/quote]那你疑惑什么,你的问题是什么,你发的帖子看了下,就是简单的介绍了下三种队列,你可以试着把你的表述弄的简洁一点[/quote] 我的我的,想都没想就提问了,我只想知道为什么只有一条核心线程工作,明明指认了最大核心线程
一个帅逼 2020-05-28
  • 打赏
  • 举报
回复
引用 5 楼 JSP_killmylife 的回复:
[quote=引用 4 楼 一个帅逼 的回复:] 线程池执行顺序 核心线程->等待队列->最大线程 ,你核心线程数就1,而且用的是LinkedBlockingQueue,当然只有一个线程能正常操作,另外一个线程任务都被存在队列中了,并不会开启新线程去执行,而SynchronousQueue这个队列其实是特殊的阻塞队列,它内部实际不会存储任务,你可以去看看SynchronousQueue的特点
这个我知道,我专门看了帖子才来发问的,帖子是这个:https://blog.csdn.net/qq_26881739/article/details/80983495 我只是很疑惑,稍微配合一下靠近业务的代码就这个效果,之前看的时候就是for循环执行线程池是没有这个问题的[/quote]那你疑惑什么,你的问题是什么,你发的帖子看了下,就是简单的介绍了下三种队列,你可以试着把你的表述弄的简洁一点
qingyuan18 2020-05-28
  • 打赏
  • 举报
回复
你的线程池容量只有1,用SynchronousQueue,两个窗口除非是完全同一时间片在发消息,否则肯定是一个线程先消费完SynchronousQueue队列然后退出了,然后第二个窗口再用池里面的线程再消费SynchronousQueue队列,当然不会阻塞,我不相信你如果是同一时间戳在发消息,用SynchronousQueue还可以并行 你可以写一个客户端来模拟,sleep下让线程不要马上退出,再试试SynchronousQueue 另外你想实现什么业务场景呢? 如果想精确的线程逻辑并且控制并发粒度,建议你用concurrent包下的各种锁,而不要依靠ExecutorThread里面的队列容器
JSP_killmylife 2020-05-28
  • 打赏
  • 举报
回复
引用 2 楼 小码人生 的回复:
释放资源问题吧。SynchronousQueue这个应该会自动释放资源,其他需要手动释放吧
我记得有个类似.close()的方法可以调用,使用这个释放吗?
JSP_killmylife 2020-05-28
  • 打赏
  • 举报
回复
引用 4 楼 一个帅逼 的回复:
线程池执行顺序 核心线程->等待队列->最大线程 ,你核心线程数就1,而且用的是LinkedBlockingQueue,当然只有一个线程能正常操作,另外一个线程任务都被存在队列中了,并不会开启新线程去执行,而SynchronousQueue这个队列其实是特殊的阻塞队列,它内部实际不会存储任务,你可以去看看SynchronousQueue的特点
这个我知道,我专门看了帖子才来发问的,帖子是这个:https://blog.csdn.net/qq_26881739/article/details/80983495 我只是很疑惑,稍微配合一下靠近业务的代码就这个效果,之前看的时候就是for循环执行线程池是没有这个问题的

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧