线程池的特点:

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

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

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

线程池的创建方式:

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. mybatis框架,使用foreach实现复杂结果的查询--循环List集合方式

    需求,根据用户角色列表  查询用户列表信息 之前我们传入的参数是Array,一个数组的形式,现在我们传入的是一个List集合,其他条件没有变化. /** * 需求:传入指定的用户角色,用户角色有1-n ...

  2. java的excel表格的导出与下载

    今天做一个java对excel表格的导出和下载的时候,从网络上搜寻了下载的模板,代码如下: 控制层: @RequestMapping(value = "excelOut_identifier ...

  3. PHP原生分页的编写

    <?php $link=mysql_connect("localhost","root","admin",'news')or die( ...

  4. Codeforces 379F New Year Tree

    F. New Year Tree time limit per test2 seconds memory limit per test256 megabytes You are a programme ...

  5. bfc与浮动元素的关系

    首先说明两个特性: 1,浮动元素兄弟元素的布局规则 当html中存在浮动元素时,其兄弟元素的布局遵循如下规则: (1)块级元素的渲染无视浮动元素 (2)文本内容或者是行内元素的渲染会考虑到浮动元素的存 ...

  6. 日常运维--rsync同步工具

    rsync命令是一个远程数据同步工具,可通过LAN/WAN快速同步多台主机间的文件.rsync使用所谓的“rsync算法”来使本地和远程两个主机之间的文件达到同步,这个算法只传送两个文件的不同部分,而 ...

  7. C/C++ 交换两个数,不使用第三个变量, 函数模板来实现

    #include <iostream> template<typename T> void exchangeTwoNumber(T &t1, T &t2): v ...

  8. 超强在线考试系统源码(私有部署&二次开发)

    随着信息化技术的发展,考试系统也在进行着深入的变革.从传统的纸质考试人工评分到现在的在线考试自动评分. 在线考试系统的应用场景也在逐渐扩宽,例如:学校的学生考试.员工培训考试.招聘考试.职称考试等等. ...

  9. C# 获得本地通用网卡信息

    可以通过使用命名空间下的ManagementObjectSearcher类及其方法Get来获得通用网卡信息. 其中,最重要的是ManagementObjectSearcher构造函数的输入参数,可以传 ...

  10. [Gamma] 项目展示

    [Gamma] 项目展示 一.工程展示 1.项目简介 定位分析 我们的目标是做一个创意分享网站,在之前的阶段中完成了大框架的搭建,并以此为基础进行界面优化与功能扩展. 典型用户 用户 面临困境 需求功 ...