Java之线程池深度剖析
1.线程池的引入
引入的好处:
1)提升性能。创建和消耗对象费时费CPU资源
2)防止内存过度消耗。控制活动线程的数量,防止并发线程过多。
使用条件:
假设在一台服务器完成一项任务的时间为T
T1 创建线程的时间
T2 在线程中执行任务的时间,包括线程间同步所需时间
T3 线程销毁的时间
显然T = T1+T2+T3。注意这是一个极度简化的假设。
可以看出T1,T3是多线程本身的带来的开销,我们渴望减少T1,T3所用的时间,从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发性)。
线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。
在Android中当同时并发多个网络线程时,引入线程池技术会极大地提高APP的性能。
2.线程池例子
1)JDK自身带有线程池的实现类ThreadPoolExecutor
2)下面是一个模拟ThreadPoolExecutor的例子,以加深对原理的理解
- public final class ThreadPool {
- // 线程池中默认线程的个数为5
- private static int worker_num = 5;
- // 工作线程
- private WorkThread[] workThreads;
- // 任务队列,作为一个缓冲,List线程不安全
- private List<Runnable> taskQueue = new LinkedList<Runnable>();
- private static ThreadPool threadPool;
- // 创建具有默认线程个数的线程池
- private ThreadPool() {
- this(5);
- }
- // 创建线程池,worker_num为线程池中工作线程的个数
- private ThreadPool(int worker_num) {
- ThreadPool.worker_num = worker_num;
- workThreads = new WorkThread[worker_num];
- for (int i = 0; i < worker_num; i++) {
- workThreads[i] = new WorkThread();
- workThreads[i].start();// 开启线程池中的线程
- }
- }
- // 单态模式,获得一个默认线程个数的线程池
- public static ThreadPool getThreadPool() {
- return getThreadPool(ThreadPool.worker_num);
- }
- // 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数
- // worker_num<=0创建默认的工作线程个数
- public static ThreadPool getThreadPool(int worker_num1) {
- if (threadPool == null)
- threadPool = new ThreadPool(worker_num1);
- return threadPool;
- }
- // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定
- public void addTask(Runnable task) {
- synchronized (taskQueue) {
- taskQueue.add(task);
- taskQueue. notifyAll();
- }
- }
- // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁
- public void destroy() {
- while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- // 工作线程停止工作,且置为null
- for (int i = 0; i < worker_num; i++) {
- workThreads[i].stopWorker();
- workThreads[i] = null;
- }
- threadPool=null;
- taskQueue.clear();// 清空任务队列
- }
- /**
- * 内部类,工作线程
- */
- private class WorkThread extends Thread {
- // 该工作线程是否有效,用于结束该工作线程
- private boolean isRunning = true;
- /*
- * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待
- */
- @Override
- public void run() {
- Runnable r = null;
- while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了
- synchronized (taskQueue) {
- while (isRunning && taskQueue.isEmpty()) {// 队列为空
- try {
- taskQueue.wait(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- if (!taskQueue.isEmpty())
- r = taskQueue.remove(0);// 取出任务
- }
- if (r != null) {
- r.run();// 执行任务
- }
- r = null;
- }
- }
- // 停止工作,让该线程自然执行完run方法,自然结束
- public void stopWorker() {
- isRunning = false;
- }
- }
- }
Java之线程池深度剖析的更多相关文章
- Android之线程池深度剖析
1.线程池的引入 引入的好处: 1)提升性能.创建和消耗对象费时费CPU资源 2)防止内存过度消耗.控制活动线程的数量,防止并发线程过多. 使用条件: 假设在一台服务器完成一 ...
- Java字节码常量池深度剖析与字节码整体结构分解
常量池深度剖析: 在上一次[https://www.cnblogs.com/webor2006/p/9416831.html]中已经将常量池分析到了2/3了,接着把剩下的分析完,先回顾一下我们编译的源 ...
- 《java学习三》并发编程 -------线程池原理剖析
阻塞队列与非阻塞队 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到 ...
- Java线程池深入理解
之前面试baba系时遇到一个相对简单的多线程编程题,即"3个线程循环输出ADC",自己答的并不是很好,深感内疚,决定更加仔细的学习<并发编程的艺术>一书,到达掌握的强度 ...
- 死磕 java线程系列之线程池深入解析——普通任务执行流程
(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 注:线程池源码部分如无特殊说明均指ThreadPoolExecutor类. 简介 前面我们一起学习了Java中 ...
- Java并发编程与技术内幕:线程池深入理解
摘要: 本文主要讲了Java当中的线程池的使用方法.注意事项及其实现源码实现原理,并辅以实例加以说明,对加深Java线程池的理解有很大的帮助. 首先,讲讲什么是线程池?照笔者的简单理解,其实就是一组线 ...
- 死磕 java线程系列之线程池深入解析——体系结构
(手机横屏看源码更方便) 注:java源码分析部分如无特殊说明均基于 java8 版本. 简介 Java的线程池是块硬骨头,对线程池的源码做深入研究不仅能提高对Java整个并发编程的理解,也能提高自己 ...
- 深入理解Java之线程池
原作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本文归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则 ...
- 深入理解Java之线程池(爱奇艺面试)
爱奇艺的面试官问 (1) 线程池是如何关闭的 (2) 如何确定线程池的数量 一.线程池销毁,停止线程池 ThreadPoolExecutor提供了两个方法,用于线程池的关闭,分别是shutdown() ...
随机推荐
- 009 spring boot中文件的上传与下载
一:任务 1.任务 文件的上传 文件的下载 二:文件的上传 1.新建一个对象 FileInfo.java package com.cao.dto; public class FileInfo { pr ...
- php(apache)切换版本
php(apache)切换版本 1.brew link php@7.1 2.上两行写入 ~/.bash_profile文件 3.source ~/.bash_profile 4.sudo vi /et ...
- SpringBoot统一错误处理
1.处理错误请求页面 import org.springframework.stereotype.Controller; import org.springframework.web.bind.ann ...
- 基于Docker的服务器搭建
-----------基于Docker的多种服务器搭建----------- 开发环境 本机上的虚拟机 Centos7.4 Docker1.13.1 Openssl1.1.1 1 Nginx 1.1 ...
- POJ 1330 Nearest Common Ancestors (模板题)【LCA】
<题目链接> 题目大意: 给出一棵树,问任意两个点的最近公共祖先的编号. 解题分析:LCA模板题,下面用的是树上倍增求解. #include <iostream> #inclu ...
- 李宏毅机器学习笔记3:Classification、Logistic Regression
李宏毅老师的机器学习课程和吴恩达老师的机器学习课程都是都是ML和DL非常好的入门资料,在YouTube.网易云课堂.B站都能观看到相应的课程视频,接下来这一系列的博客我都将记录老师上课的笔记以及自己对 ...
- EF Core中的多对多映射如何实现?
EF 6.X中的多对多映射是直接使用HasMany-HasMany来做的.但是到了EF Core中,不再直接支持这种方式了,可以是可以使用,但是不推荐,具体使用可以参考<你必须掌握的Entity ...
- BZOJ.2159.Crash的文明世界(斯特林数 树形DP)
BZOJ 洛谷 挺套路但并不难的一道题 \(Description\) 给定一棵\(n\)个点的树和\(K\),边权为\(1\).对于每个点\(x\),求\(S(x)=\sum_{i=1}^ndis( ...
- tomcat环境变量详细配置步骤
这篇文章主要为大家详细介绍了tomcat环境变量配置步骤,包括JDK环境变量配置,感兴趣的小伙伴们可以参考一下 本文实例为大家分享了tomcat环境变量的配置教程,供大家参考,具体内容如下 1.=== ...
- BZOJ3531[Sdoi2014]旅行——树链剖分+线段树
题目描述 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰.为了方便,我们 ...