阿里推荐原因:使用线程池可以减少创建和销毁线程上所花的时间以及系统资源的开销,然后之所以不用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的更多相关文章

  1. 从源码看JDK提供的线程池(ThreadPoolExecutor)

    一丶什么是线程池 (1)博主在听到线程池三个字的时候第一个想法就是数据库连接池,回忆一下,我们在学JavaWeb的时候怎么理解数据库连接池的,数据库创建连接和关闭连接是一个比较耗费资源的事情,对于那些 ...

  2. 线程中断方法interrupt() 与 cancel()

    (一).关于interrupt()     interrupt()并不直接中断线程,而是设定一个中断标识,然后由程序进行中断检查,确定是否中断.     1. sleep() & interr ...

  3. 线程池之ThreadPoolExecutor详解

    为什么要使用线程池 线程是一个操作系统概念.操作系统负责这个线程的创建.挂起.运行.阻塞和终结操作.而操作系统创建线程.切换线程状态.终结线程都要进行CPU调度——这是一个耗费时间和系统资源的事情.  ...

  4. Java并发包线程池之ThreadPoolExecutor

    参数详解 ExecutorService的最通用的线程池实现,ThreadPoolExecutor是一个支持通过配置一些参数达到满足不同使用场景的线程池实现,通常通过Executors的工厂方法进行配 ...

  5. 线程池之 ThreadPoolExecutor

    线程池之 ThreadPoolExecutor + 面试题 线程池介绍 线程池(Thread Pool):把一个或多个线程通过统一的方式进行调度和重复使用的技术,避免了因为线程过多而带来使用上的开销. ...

  6. Android线程管理之ThreadPoolExecutor自定义线程池

    前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...

  7. 线程池:ThreadPoolExecutor

    [ThreadPoolExecutor的使用和思考]   public ThreadPoolExecutor(int corePoolSize,                             ...

  8. 从源码解读线程(Thread)和线程池(ThreadPoolExecutor)的状态

    线程是比进程更加轻量级的调度执行单位,理解线程是理解并发编程的不可或缺的一部分:而生产过程中不可能永远使用裸线程,需要线程池技术,线程池是管理和调度线程的资源池.因为前不久遇到了一个关于线程状态的问题 ...

  9. Java并发编程:Java线程池核心ThreadPoolExecutor的使用和原理分析

    目录 引出线程池 Executor框架 ThreadPoolExecutor详解 构造函数 重要的变量 线程池执行流程 任务队列workQueue 任务拒绝策略 线程池的关闭 ThreadPoolEx ...

随机推荐

  1. MySQL复制表-INSERT INTO SELECT

    基础table为: mysql> select * from staff; +----+----------+-------+ | id | name | slary | +----+----- ...

  2. ubuntu Fcitx 输入法 选择 黑框问题 解决方案

    在虚拟机装了个xubuntu,弄好fcitx 输入法后,打字时看不到选择框,被黑框折腾的不行,后来了一个方法,暂时解决了问题. 用 killall fcitx-qimpanel 结束 fcitx-qi ...

  3. PHP选择排序

    选择排序,非常的直观,也相对简单. 思路如下: 假设,从小到大排序. 首先,第一轮循环,从所有数组中,找出最小的元素,然后将其下标记录下来. 然后,确定不是第一个元素,则和第一个元素进行交换. 接下来 ...

  4. opencv学习之路(34)、SIFT特征匹配(二)

    一.特征匹配简介 二.暴力匹配 1.nth_element筛选 #include "opencv2/opencv.hpp" #include <opencv2/nonfree ...

  5. 为基于OpenCV的图像处理程序编写界面—关于QT\MFC\CSharp的选择以及GOCW的介绍

            基于OpenCV编写图像处理项目,除了算法以外,比较重要一个问题就是界面设计问题.对于c++语系的程序员来说,一般来说有QT/MFC两种考虑.QT的确功能强大,特别是QML编写andr ...

  6. L1,L2正则化代码

    # L1正则 import numpy as np from sklearn.linear_model import Lasso from sklearn.linear_model import SG ...

  7. cv2.getRotationMatrix2D函数

  8. Java包装类介绍与类型之间相互转换

    1.包装类存在的意义 通俗解释就是由于Java是面对对象的语言,而基本类型不具有面对对象的概念,为了弥补不足,引入了包装类方便使用面对对象的变成思想操作基本类型. 2.基本类型和包装类对应关系 byt ...

  9. vscode下运行matlab记录

    Linux下安装MATLAB可参照以下链接: https://blog.csdn.net/qq_31285709/article/details/82083902 在vscode 中运行.m文件. 首 ...

  10. AT2412 最大の和

    传送门 思路: 线段树暴力枚举区间,查询最大区间和. Code: #include<iostream> #include<cstdio> #include<algorit ...