线程池的特点:

降低资源:通过重复利用已创建的线程降低线程创建和销毁的损耗

提高效率:当任务到底时,不需要等待,立即执行

方便管理:统一分配,调优和监控等

线程池的创建方式:

1.CachedThreadPool:创建一个可缓存线程池,灵活回收空闲线程

public class ThreadPoolDemo {
public static void main(String[] args) {
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int temp = i;
newCachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "->" + temp);
}
});
}
}
}

打印后可以发现:同一个线程有被再次利用,线程池理论大小是无限的

2.FixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待

        ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);

其他代码不变,打印发现五个线程都在复用

3.ScheduledThreadPool:支持定时性地执行任务

public class ThreadPoolDemo {
public static void main(String[] args) {
ScheduledExecutorService newScheduledThreadPool = Executors.newScheduledThreadPool(5);
for (int i = 0; i < 10; i++) {
final int temp = i;
newScheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "->" + temp);
}
}, 3, TimeUnit.SECONDS);
}
}
}

观察打印:等待3s后打印

4.SingleThreadExecutor:单线程

        ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();

打印发现只调用了一个线程

线程池的原理:

四种方式都走了ThreadPoolExecutor的构造方法:

    public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
    public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}

corePoolSize:最大核心线程数:实际运用线程数

maximumPoolSize:最大线程数:线程池最多创建线程数

如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务

如果当前线程池中的线程数目>=corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列当中,若添加成功,则该任务会等待空闲线程将其取出去执行;若添加失败(一般来说是任务缓存队列已满),则会尝试创建新的线程去执行这个任务;

如果队列已经满了,则在总线程数不大于maximumPoolSize的前提下,则创建新的线程;

如果当前线程池中的线程数目达到maximumPoolSize,则会采取任务拒绝策略进行处理;

如果线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止,直至线程池中的线程数目不大于corePoolSize;如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止。

写一段代码来理解:

public class MyThreadPool {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
//核心线程数为1
1,
//最大线程数为2
2,
//保持存活时间0毫秒,意思是用完不回收
0L, TimeUnit.MILLISECONDS,
//阻塞队列
new LinkedBlockingQueue<Runnable>(3));
threadPoolExecutor.execute(new TaskThread("task1"));
threadPoolExecutor.execute(new TaskThread("task2"));
threadPoolExecutor.execute(new TaskThread("task3"));
}
} class TaskThread implements Runnable {
private String threadName; TaskThread(String threadName) {
this.threadName = threadName;
} @Override
public void run() {
System.out.println(threadName);
}
}

提交task1时候,创建一个线程直接执行,此时核心线程数等于存在线程数

提交task2时候,存放在队列缓存,此时存在线程数等于最大线程数

提交task3时候,也存放在队列中缓存,而我阻塞队列大小是3,现在只存放了两个,所以不会报错

理论上,提交到task5都不会报错,最大线程数2+队列大小3=5;但是提交task6一定会报错

另外一点:如果提交到task4,打印线程名称:发现只调用了线程1,第2个线程没有调用过

因为:task1提交时候,task2,task3,task4存放在队列中,恰好到达队列最大值,所以不创建新线程,而是线程1依次执行这三个任务

合理配置线程池:

原则:

CPU密集:任务需要大量的运算,但没有阻塞的情况,CPU可以全速运行

IO密集:任务需要大量的IO操作,产生阻塞

CPU密集型线程数越少越好,最好配置为CPU核心数量

IO密集型线程数要尽量多,最好配置为CPU核心数量*2

Java深入学习(3):线程池原理的更多相关文章

  1. java多线程系列(六)---线程池原理及其使用

    线程池 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 java多线程系列(三)之等待通知 ...

  2. Java多线程学习之线程池源码详解

    0.使用线程池的必要性 在生产环境中,如果为每个任务分配一个线程,会造成许多问题: 线程生命周期的开销非常高.线程的创建和销毁都要付出代价.比如,线程的创建需要时间,延迟处理请求.如果请求的到达率非常 ...

  3. JAVA多线程学习七-线程池

    为什么用线程池 1.创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率 例如: 记创建线程消耗时间T1,执行任务消耗时间T2,销毁线程消耗时间T3 如果T1+T3> ...

  4. 《java学习三》并发编程 -------线程池原理剖析

    阻塞队列与非阻塞队 阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞.试图从空的阻塞队列中获取元素的线程将会被阻塞,直到 ...

  5. Java 线程池原理分析

    1.简介 线程池可以简单看做是一组线程的集合,通过使用线程池,我们可以方便的复用线程,避免了频繁创建和销毁线程所带来的开销.在应用上,线程池可应用在后端相关服务中.比如 Web 服务器,数据库服务器等 ...

  6. Java 并发编程——Executor框架和线程池原理

    Eexecutor作为灵活且强大的异步执行框架,其支持多种不同类型的任务执行策略,提供了一种标准的方法将任务的提交过程和执行过程解耦开发,基于生产者-消费者模式,其提交任务的线程相当于生产者,执行任务 ...

  7. Java 并发编程——Executor框架和线程池原理

    Java 并发编程系列文章 Java 并发基础——线程安全性 Java 并发编程——Callable+Future+FutureTask java 并发编程——Thread 源码重新学习 java并发 ...

  8. Java线程池原理解读

    引言 引用自<阿里巴巴JAVA开发手册> [强制]线程资源必须通过线程池提供,不允许在应用中自行显式创建线程. 说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销 ...

  9. 手写一个线程池,带你学习ThreadPoolExecutor线程池实现原理

    摘要:从手写线程池开始,逐步的分析这些代码在Java的线程池中是如何实现的. 本文分享自华为云社区<手写线程池,对照学习ThreadPoolExecutor线程池实现原理!>,作者:小傅哥 ...

  10. java多线程系类:JUC线程池:03之线程池原理(二)(转)

    概要 在前面一章"Java多线程系列--"JUC线程池"02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包 ...

随机推荐

  1. Python并发编程之进程同步

    """ 问题:当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱的问题 """ ''' 进程同步 ''' #多进程抢占输出资源 ...

  2. JZOJ3492数数&&GDOI2018超级异或绵羊——位&&类欧几里得

    JZOJ3492 数数(count) 我们知道,一个等差数列可以用三个数A,B,N表示成如下形式:  B+A,B+2A,B+3A⋯B+NA ztxz16想知道对于一个给定的等差数列,把其中每一项用二进 ...

  3. python基础之五:dict 字典

    1.数据类型的划分:可变数据类型.不可变数据类型 不可变的有:元组(tuple).字符(str).整型(int).布尔型(bool) 它们都可以哈希 可变的:列表(list).set.字典(dict) ...

  4. redhat quay 安装试用

    最近redhat 开源了quay 容器镜像管理平台,参考官方文档跑的时候需要订阅,各种不好使,然后就自己基于源码构建了 一个镜像(使用官方的dockerfile,构建出来的太大了1.9G 以及push ...

  5. attribute和property的区别是什么?

          attribute                                       property 标签属性 对应html                       对象属 ...

  6. 原生js给同一对象绑定多个事件

    事件监听 var son = document.querySelector(".son"); son.addEventListener('click', once1); funct ...

  7. go 优秀文档

    go语言资料汇总 : https://blog.zhnytech.com/articles/2016/07/15/Golang%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99% ...

  8. PS 个人常用功能

    PS是什么? Adobe Photoshop,简称"PS",是由Adobe Systems开发和发行的图像处理软件. 不是美工,为什么要学PS? 1)写博客时,有些需要的素材图片有 ...

  9. Python【每日一问】29

    问: [基础题]:给一个不多于 5 位的正整数,要求:一.求它是几位数,二.逆序印出各位数字[提高题]:某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:每位数字都加 ...

  10. QuantLib 金融计算——基本组件之 ExchangeRate 类

    目录 QuantLib 金融计算--基本组件之 ExchangeRate 类 概述 构造函数 成员函数 如果未做特别说明,文中的程序都是 python3 代码. QuantLib 金融计算--基本组件 ...