博主信息
富贵人生
博文
87
粉丝
0
评论
0
访问量
2981
积分:0
P豆:174

什么是线程池?

2021年10月15日 22:30:30阅读数:25博客 / 富贵人生

什么是线程池?

线程池就是创建若干个可执行的线程放入一个池(容器)中,有任务需要处理时,会提交到线程池中的任务队列,处理完之后线程并不会被销毁,而是仍然在线程池中等待下一个任务。

 

为什么要使用线程池?

因为 Java 中创建一个线程,需要调用操作系统内核的 API,操作系统要为线程分配一系列的资源,成本很高,所以线程是一个重量级的对象,应该避免频繁创建和销毁。
使用线程池就能很好地避免频繁创建和销毁。

 

线程池是一种生产者——消费者模式

先看下一个简单的 Java 线程池的代码

package com.yiidian.concurrency.a010;import java.util.ArrayList;import java.util.List;import java.util.concurrent.BlockingQueue;/**
* 简单的线程池
* @author yiidian
*/public class ThreadPool {    
   //阻塞队列实现生产者-消费者
   BlockingQueue<Runnable> taskQueue;    
   //工作线程集合
   List<Thread> threads = new ArrayList<Thread>();    
   //线程池的构造方法
   ThreadPool(int poolSize, BlockingQueue<Runnable> taskQueue) {        this.taskQueue = taskQueue;        
       //启动线程池对应 size 的工作线程
       for (int i = 0; i <poolSize; i++) {
           Thread t = new Thread(() -> {                while (true) {
                   Runnable task;                    try {
                       task = taskQueue.take();//获取任务队列中的下一个任务
                       task.run();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }
           });
           t.start();
           threads.add(t);
       }
   }    
   //提交执行任务
   void execute(Runnable task) {        try {            //把任务方法放到任务队列
           taskQueue.put(task);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
   }

}

 

线程池的使用测试

package com.yiidian.concurrency.a010;import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingQueue;/**
* 测试线程池的使用
* @author yiidian
*/public class TestThreadPool {    public static void main(String[] args) {        // 创建有界阻塞任务队列
       BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>(10);        // 创建 3个 工作线程的线程池
       ThreadPool tp = new ThreadPool(3, taskQueue);        
       //提交 10 个任务
       for (int i = 1; i <= 10; i++) {            final int j = i;
           tp.execute(() -> {
               System.out.println("执行任务" + j);
           });
       }
   }

}

打印结果

执行任务1执行任务2执行任务3执行任务6执行任务5执行任务4执行任务8执行任务7执行任务10执行任务9

这个线程池的代码中

poolSize 是线程池工作线程的个数BlockingQueue taskQueue 是用有界阻塞队列存储 Runnable 任务execute(Runnable task) 提交任务线程池对象被创建,游戏账号拍卖平台地图就自动启动 poolSize 个工作线程工作线程一直从任务队列 taskQueue 中取任务


线程池的原理就是这么简单,但是 JDK 中的线程池的功能,要远比这个强大的多。

 

JDK 中线程池的使用

JDK 中提供的最核心的线程池工具类 ThreadPoolExecutor,在 JDK 1.8 中这个类最复杂的构造方法有 7 个参数。

ThreadPoolExecutor(    int corePoolSize,    int maximumPoolSize,    long keepAliveTime,
   TimeUnit unit,
   BlockingQueue<Runnable> workQueue,
   ThreadFactory threadFactory,
   RejectedExecutionHandler handler)
corePoolSize:线程池保有的最小线程数。maximumPoolSize:线程池创建的最大线程数。keepAliveTime:上面提到项目根据忙闲来增减人员,那在编程世界里,如何定义忙和闲呢?很简单,一个线程如果在一段时间内,都没有执行任务,说明很闲,keepAliveTime 和 unit 就是用来定义这个“一段时间”的参数。也就是说,如果一个线程空闲了keepAliveTime & unit这么久,而且线程池的线程数大于 corePoolSize ,那么这个空闲的线程就要被回收了。unit:keepAliveTime 的时间单位workQueue:任务队列threadFactory:线程工厂对象,可以自定义如何创建线程,如给线程指定name。handler:自定义任务的拒绝策略。线程池中所有线程都在忙碌,且任务队列已满,线程池就会拒绝接收再提交的任务。handler 就是拒绝策略,包括 4 种(即RejectedExecutionHandler 接口的 4个实现类)。AbortPolicy:默认的拒绝策略,throws RejectedExecutionExceptionCallerRunsPolicy:提交任务的线程自己去执行该任务DiscardPolicy:直接丢弃任务,不抛出任何异常DiscardOldestPolicy:丢弃最老的任务,加入新的任务


JDK 的并发工具包里还有一个静态线程池工厂类 Executors,可以方便地创建线程池,但是由于 Executors 创建的线程池内部很多地方用到了无界任务队列,在高并发场景下,无界任务队列会接收过多的任务对象,导致 JVM 抛出OutOfMemoryError,整个 JVM 服务崩溃,影响严重。所以很多公司已经不建议使用 Executors 去创建线程。

 

Executors 的简介

虽然不建议使用,作为对 JDK 的学习,还是简单介绍一下.

newFixedThreadPool:创建定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程newCachedThreadPool:创建可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制newScheduledThreadPool:创建定长线程池,可执行周期性的任务newSingleThreadExecutor:创建单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行newSingleThreadScheduledExecutor:创建单线程可执行周期性任务的线程池newWorkStealingPool:任务可窃取线程池,不保证执行顺序,当有空闲线程时会从其他任务队列窃取任务执行,适合任务耗时差异较大。


版权申明:本博文版权归博主所有,转载请注明地址!如有侵权、违法,请联系admin@php.cn举报处理!

全部评论

文明上网理性发言,请遵守新闻评论服务协议

条评论
  • java创建线的四种方式:1、newCachedThreadPool创建一个可缓存线;2、newFixedThreadPool创建一个定长线;3、newScheduledThreadPool
    本篇文章给大家介绍一下Redis,探讨一下为Redis线,Redis为快。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
    Java中的线通过Java.lang.Thread来实现的,可以通过实例化Thread一个对象来创建一个线,然后再调用start()启动,但Thread的一个特定的方法run()也可以启动线
    线一种多线处理形式,处理过中将任务提交到线,任务的执行交由线来管理。
    本篇文章给大家分享一分钟解读phpMyAdmin?它的使用教?(分享)有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
    前端序员,后端序员,全站序员分别都?找工作到底选前端还后端?为美国很多都全站序员呢?带着这些疑问,本文来给大家一一解答,保证让你对这些概念搞的明明白白!
    在文中,我将教你 docker,为使用以及怎样用来给 nodejs 序打包。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
    与数据库线类似,如果没有数据库连接,那每次对数据库的连接都要new来获取连接。重复的连接和释放操作会消费大量的系统资源,我们可以使用数据库连接,直接去中取连接
    PHP版本分为Non Thread Safe和Thread Safe,Non Thread Safe指非线安全,Thread Safe线安全,区别?如何选择?
    java面试题及答案:ArrayList和Vector的区别?Vector线安全的,也就它的方法之间线同步的,而ArrayList线序不安全的,它的方法之间线不同步的。
    采用连接大大节省了不断创建与销毁线的开销,这就有名的「化」思想,不管线 HTTP 连接,都能看到它的身影。
    方法:newCachedThreadPool创建可缓存线、newFixedThreadPool创建定长线、newScheduledThreadPool创建定长线、newSingleThreadExecutor
    指令计算机能实现的基本操作,指挥机器工作的指示和命令,指令均为二进制数形式;指令由操作码和地址码组成,操作码告诉计算机执行操作,地址码告诉计算机到哪个存储单元地址中读取参与操作的数据。
    swoole教栏目介绍进应用序的启动实例。独立的文件资源,数据资源,内存空间。线线属于进序的执行者。一个进至少包含一个主线,也可以有更多的子线
    序的5大特性为:1、有穷性,一个算法的操作步骤有限的,不能无限的;2、确定性,算法中的每一个步骤都要确定的词,不能含糊不清;3、输入,执行算法需要;4、输出,序需要得出的结果;5、有效性,
    下载php解释器版本有两种,线安全和非线安全,线安全给apache用的,非线安全给iis用的,我们要配的iis,所以下载非线安全的,x86和x64看自己的机器系统选择对应的版本下载就行了
    1、java中==和equals和hashCode的区别 ; 2、int与integer的区别 ; 3、String、StringBuffer、StringBuilder区别 ; 4、内部类?
    黑金电指超威集团推出的黑金高能量电,这种电将石墨烯用在了电的板栅里面。此后,黑金电经过三代产品升级,对板栅结构、固化工艺、电解液酸配比等6项指标进行了优化升级。
    我们学习了解了这多关于PHP的知识,不知道你们php中如何调用存储函数?调用存储过?其中触发器否已经完全掌握了呢,如果没有,那就跟随本篇文章一起继续学习吧
    序安全补丁级别日期,说明关于Android系统内部安全问题的修复内容;这个新增项对于户使用来说并不会带来影响。安全补丁级别类似Windows系统更新安装各种补丁,也属于漏洞修复的另一种方式。