阿里推荐的线程使用方法 ThreadPoolExecutor
阿里推荐原因:使用线程池可以减少创建和销毁线程上所花的时间以及系统资源的开销,然后之所以不用Executors自定义线程池,用ThreadPoolExecutor是为了规范线程池的使用,还有让其他人更好懂线程池的运行规则。
先说一下关于线程的概念
任务:线程需要执行的代码,也就是Runnable
任务队列:线程满了,就任务就放入任务队列里等待,等其他任务在线程里执行完,这个线程就空出来了,任务队列就将最早来的未执行的任务放入线程执行。
核心线程:线程池一直存在的线程
最大线程数量:指的是线程池所容纳的最多的线程数量
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue)
第一个是核心线程数量,第二个是最大线程数量,第三个是非核心线程的闲置超时时间,超过这个时间就会被回收,第四个是线程池中的任务队列模式。
我们主要讲这个任务队列模式
1.LinkedBlockingDeque
我先上一个例子代码,再来唠嗑
public class MainActivity extends AppCompatActivity {
Button button;
ThreadPoolExecutor executor;
Runnable myRunnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + " run");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.btn_record_video);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
executor.execute(myRunnable);
executor.execute(myRunnable);
executor.execute(myRunnable);
}
});
executor = new ThreadPoolExecutor(3, 6, 3, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
}
}
当我们点击一次按钮
03-03 15:00:43.503 5292-5333/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:00:43.505 5292-5335/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:00:43.505 5292-5334/com.example.zth.seven I/System.out: pool-1-thread-2 run
连续点击两次
03-03 15:10:47.941 7114-7259/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:10:47.941 7114-7260/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:10:47.942 7114-7261/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:10:49.942 7114-7260/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:10:49.942 7114-7259/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:10:49.942 7114-7261/com.example.zth.seven I/System.out: pool-1-thread-3 run
这个时候就可以看出虽然说是最大线程数量是6,但是只用核心线程,不创建新线程,如果核心线程用完了就在队列里等待,队列的大小没有限制(你可随便点,他反正后来都会执行)
但是还没完这个LinkedBlockingDeque还可以设置队列数量,如果我把队列设置为2
executor = new ThreadPoolExecutor(3, 6, 3,
TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(2));
然后连续点击2两次
03-03 15:19:39.851 8971-9013/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:19:39.851 8971-9014/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:19:39.851 8971-9015/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:19:40.045 8971-9016/com.example.zth.seven I/System.out: pool-1-thread-4 run
03-03 15:19:41.851 8971-9013/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:19:41.851 8971-9015/com.example.zth.seven I/System.out: pool-1-thread-3 run
他这个时候能够创建四个线程了,为何,首先第一次点击占了三个核心线程,然后第二次点击将前两次任务放入队列里,然后队列满了就创建一个新线程用来执行最后一个任务
如果我们连续点击三次,程序在我们点击第三次就崩溃了,因为线程数量超出最大线程数量了
总结:LinkedBlockingDeque就首先使用核心线程,核心线程用完了就把任务放入队列里等待,如果队列满了就创建新线程,注意不设置队列数量,他就默认无限大。
2.SynchronousQueue
我们还是和以前一样换掉一行代码
executor = new ThreadPoolExecutor(3, 6, 3,
TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
点击一次
03-03 15:39:31.915 12403-12446/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:39:31.915 12403-12447/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:39:31.915 12403-12445/com.example.zth.seven I/System.out: pool-1-thread-1 run
连续点击两次
03-03 15:39:53.204 12403-12446/com.example.zth.seven I/System.out: pool-1-thread-2 run
03-03 15:39:53.204 12403-12445/com.example.zth.seven I/System.out: pool-1-thread-1 run
03-03 15:39:53.204 12403-12447/com.example.zth.seven I/System.out: pool-1-thread-3 run
03-03 15:39:53.371 12403-12501/com.example.zth.seven I/System.out: pool-1-thread-5 run
03-03 15:39:53.371 12403-12502/com.example.zth.seven I/System.out: pool-1-thread-6 run
03-03 15:39:53.371 12403-12500/com.example.zth.seven I/System.out: pool-1-thread-4 run
可以看出来当核心线程占满时他没有将任务放入队列里去等待,而是直接创建新线程取执行任务
连续点击三次
程序崩溃,因为他创建的线程超过了最大线程数量,
总结:SynchronousQueue很单纯,不使用队列,核心线程用完了就创建新线程,
参考文章:
http://blog.csdn.net/qq_25806863/article/details/71126867
阿里推荐的线程使用方法 ThreadPoolExecutor的更多相关文章
- 从源码看JDK提供的线程池(ThreadPoolExecutor)
一丶什么是线程池 (1)博主在听到线程池三个字的时候第一个想法就是数据库连接池,回忆一下,我们在学JavaWeb的时候怎么理解数据库连接池的,数据库创建连接和关闭连接是一个比较耗费资源的事情,对于那些 ...
- 线程中断方法interrupt() 与 cancel()
(一).关于interrupt() interrupt()并不直接中断线程,而是设定一个中断标识,然后由程序进行中断检查,确定是否中断. 1. sleep() & interr ...
- 线程池之ThreadPoolExecutor详解
为什么要使用线程池 线程是一个操作系统概念.操作系统负责这个线程的创建.挂起.运行.阻塞和终结操作.而操作系统创建线程.切换线程状态.终结线程都要进行CPU调度——这是一个耗费时间和系统资源的事情. ...
- Java并发包线程池之ThreadPoolExecutor
参数详解 ExecutorService的最通用的线程池实现,ThreadPoolExecutor是一个支持通过配置一些参数达到满足不同使用场景的线程池实现,通常通过Executors的工厂方法进行配 ...
- 线程池之 ThreadPoolExecutor
线程池之 ThreadPoolExecutor + 面试题 线程池介绍 线程池(Thread Pool):把一个或多个线程通过统一的方式进行调度和重复使用的技术,避免了因为线程过多而带来使用上的开销. ...
- Android线程管理之ThreadPoolExecutor自定义线程池
前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...
- 线程池:ThreadPoolExecutor
[ThreadPoolExecutor的使用和思考] public ThreadPoolExecutor(int corePoolSize, ...
- 从源码解读线程(Thread)和线程池(ThreadPoolExecutor)的状态
线程是比进程更加轻量级的调度执行单位,理解线程是理解并发编程的不可或缺的一部分:而生产过程中不可能永远使用裸线程,需要线程池技术,线程池是管理和调度线程的资源池.因为前不久遇到了一个关于线程状态的问题 ...
- Java并发编程:Java线程池核心ThreadPoolExecutor的使用和原理分析
目录 引出线程池 Executor框架 ThreadPoolExecutor详解 构造函数 重要的变量 线程池执行流程 任务队列workQueue 任务拒绝策略 线程池的关闭 ThreadPoolEx ...
随机推荐
- leetcode 二进制求和 python
class Solution: def addBinary(self, a, b): """ :type a: str :type b: str :rtype: str ...
- 防止sql注入(简单)
(1)mysql_real_escape_string -- 转义 SQL 语句中使用的字符串中的特殊字符,并考虑到连接的当前字符集 使用方法如下: $sql = "select count ...
- ipv4网络无访问权限
昨天折腾了一天这个网络受限问题,都没有得到解决,驱动精灵.电脑管家(我不用360).重置Winsock目录.网络重置.组策略控制台.重启路由器(学校的以太网,工作时间不好重置路由器)都用了个遍,一直都 ...
- Java 问题定位工具 ——jstack
简介 jstack 主要用于生成虚拟机当前时刻的「线程快照」.线程快照是当前 Java 虚拟机每一条线程正在执行的方法堆栈的集合. 生成线程快照的主要目的是用于定位线程出现长时间停顿的原因,如线程间死 ...
- 安装与配置apache WEB服务器(Linux环境)
Linux环境下安装一个软件的方式多数为两种: 1.通过命令从远程源下载自动默认安装 2.编译安装 第一种较为简单,直接通过 yum 或者 apt-get 直接安装即可,但是对我来说,编译安装可能更加 ...
- 在线预览-Java 使用 Print2Flash 实现Office文档在线阅读
近期项目上遇到一个需求是用户上传的文档进行在线浏览,之前有过一篇使用 OpenOffice 将 word 转换成 html 页面进行展示的.现在介绍一个新的工具那就是 Print2Flash . ...
- Vue-admin工作整理(十一):Vuex-动态注册模块
概述: 动态注册模块分为两种,一种是在根state下注册一个模块,一种是在模块下再自动注册一个模块 第一种:根state下动态注册模块: 思路:通过store来实现,this.$store来获取当前的 ...
- 如何查找redis使用的是哪个配置文件
ps -ef|grep redis 得到了进程号 xxxx 然后 ls -l /proc/xxxx/cwd ps:可以推广到其他进程,只要有pid,就能找到配置文件
- Java面试题之Java基础
1. JDK 和 JRE 有什么区别? JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台.所有的Java 程序都要在JRE下才能运行.普通用户只需要运行已开 ...
- js实现bind方法
//目标函数 function fun(...args) { console.log(this); console.log(args); } //目标函数原型对象上的一个方法cher func.pro ...