范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

线程池的线程是如何复用的

  前言
  进程和线程的关系相信大家都知道,这里我就不做过多的解释了,既然一个进程是由多个线程组成的,那么线程池又是由若干个线程队列组成的,在并发量比较高的情景下,我们通常会去创建线程池就执行任务,而不单一的创建多个线程去执行任务,因为线程的创建的一系列动作,是需要资源开销的,如果频繁的对线程创建销毁,其实本身是一种很浪费资源的,就更谈不上提高效率了。
  一般都会创建线程池将线程统一管理,并且还会引入阻塞和非阻塞队列,接收需要排队处理的任务,但是线程池里的线程是在处理完任务就会进行销毁么,其实并不是这样的,下面我们一起来对线程池里线程是如何复用的进行分析。使用线程池使用线程池原因
  1.复用已创建的线程,减少线程创建、销毁开销。 2.可以根据自身系统的承载能力,合理对线程池线程数量进行控制。 3.控制并发数,保护系统。private static void creatThreadPool() throws InterruptedException {     List threadList = new ArrayList<>();     long start = System.currentTimeMillis();     log.info("创建线程池开始");     for (int i = 0; i < 100; i++) {         Thread thread = new Thread(() -> {             try {                 TimeUnit.SECONDS.sleep(10);              } catch (InterruptedException e) {                 e.printStackTrace();             }         }, "thread" + i);         thread.start();         threadList.add(thread);         TimeUnit.MILLISECONDS.sleep(1);     }     long end = System.currentTimeMillis();     long needTime = end - start;     log.info("创建100个线程所花费的时间:" + needTime + "ms");  }  public static void main(String[] args) throws InterruptedException {     creatThreadPool(); }  复制代码
  创建100个线程需要264ms,平均一个线程的创建需要2.2ms左右,线程执行任务可以只需要不到1ms,那么这样看来创建线程是不划算的。
  这里除里JDK自带的四种线程池类型,简单介绍下jdk自带四种线程池。
  1.newCachedThreadPool:可缓存的的无界线程池,可以自动线程回收,通常执行短期异步的任务。
  2.newFixThreadPool:固定数量的线程池,控制并发数。
  3.newSingleThreadPool:单线程工作的线程池,所有任务按照FIFO先进先出的原则执行。
  4.newScheduleThreadPool:可定期执行的线程池,可指定执行时间和执行次数。
  通常情况下,在阿里的开发手册上写不推荐使用Executors创建线程,也就是线程池的顶级接口,jdk自带的线程池创建的时候是没有核心线程数的,不断的创建对象,那么就会存在内存溢出的风险。线程池的工作流程
  一般创建线程池还是使用ThreadPoolExecutor创建,它的上接口是ExecutorService,所有说真正创建线程池是用ExecutorService创建。 7大核心参数这里就不多说了,直接说线程池的工作流程。
  1.首先当运行的线程池 corePoolSize(核心线程数),任务放入队列。
  3.队列已满,当前运行的线程数 MaxImumPoolSize(最大线程数),使用Handler拒绝策略,当然不能丢弃任务,一般使用CallerRunsPolicy使用调用线程执行任务。
  4.当前线程不需要执行任务,也不能让它一直存在着占用资源,超出keepAliveTime,运行线程数> corePoolSize,这线程会被回收掉,这样做主要是控制核心线程里线程数量。线程复用
  首先看ThreadPoolExecutor源码,execute线程池执行入口   public void execute(Runnable command) {         if (command == null)             throw new NullPointerException();       //当前线程数小于核心线程数         int c = ctl.get();         if (workerCountOf(c) < corePoolSize) {             if (addWorker(command, true))                 return;             c = ctl.get();         }     //加入等待队列里排队处理         if (isRunning(c) && workQueue.offer(command)) {             int recheck = ctl.get();       //检查工作线程停止工作是否需要移除,触发拒绝策略             if (! isRunning(recheck) && remove(command))                 reject(command);      //二次检查             else if (workerCountOf(recheck) == 0)                 addWorker(null, false);         }      //无法提交线程则触发拒绝策略         else if (!addWorker(command, false))             reject(command);     } 复制代码
  这里看到每个if判断里都存在addWorker方法,那么这个方法肯定是线程是否复用的重点,Worker w = null; try {      //将任务放到Worker工作线程里面,     w = new Worker(firstTask);     final Thread t = w.thread;     if (t != null) {         final ReentrantLock mainLock = this.mainLock;         mainLock.lock();         try {             // Recheck while holding lock.             // Back out on ThreadFactory failure or if             // shut down before lock acquired.             int rs = runStateOf(ctl.get());              if (rs < SHUTDOWN ||                 (rs == SHUTDOWN && firstTask == null)) {                 if (t.isAlive()) // precheck that t is startable                     throw new IllegalThreadStateException();         //hashset 集合里存放 Worker对象                 workers.add(w);                 int s = workers.size();                 if (s > largestPoolSize)                     largestPoolSize = s;                 workerAdded = true;             }         } finally {             mainLock.unlock();         }         if (workerAdded) {             t.start();             workerStarted = true;         }     } } finally {     if (! workerStarted)         addWorkerFailed(w); } return workerStarted;  复制代码
  Worker是个final修饰的内部类,意味着不能被其他类继承,那么线程复用只能在这一个类里面进行,接着看Worker的run方法里面执行的runWorker方法,这个是线程复用的核心方法。final void runWorker(Worker w) {     Thread wt = Thread.currentThread();    //获取线程里面执行的任务     Runnable task = w.firstTask;     w.firstTask = null;     w.unlock(); // allow interrupts     boolean completedAbruptly = true;     try {        //如果任务不为空  || 重新拿取线程里的任务         while (task != null || (task = getTask()) != null) {             w.lock();             // If pool is stopping, ensure thread is interrupted;             // if not, ensure thread is not interrupted.  This             // requires a recheck in second case to deal with             // shutdownNow race while clearing interrupt            //判断线程的状态,并执行对应的拒绝策略             if ((runStateAtLeast(ctl.get(), STOP) ||                  (Thread.interrupted() &&                   runStateAtLeast(ctl.get(), STOP))) &&                 !wt.isInterrupted())                 wt.interrupt();             try {                 beforeExecute(wt, task);                 Throwable thrown = null;                 try {                     task.run();                 } catch (RuntimeException x) {                     thrown = x; throw x;                 } catch (Error x) {                     thrown = x; throw x;                 } catch (Throwable x) {                     thrown = x; throw new Error(x);                 } finally {                     afterExecute(task, thrown);                 }             } finally {                 task = null;                 w.completedTasks++;                 w.unlock();             }         }         completedAbruptly = false;     } finally {         processWorkerExit(w, completedAbruptly);     }  复制代码
  getTask方法重新拿取线程里的任务, 前面一系列的判断主要是来检查线程的状态,以及线程池线程的数量,其核心主要是线程数量是否超过了核心线程数,如果超过了则会进入workQueue工作队列,workQueue.poll非核心线程会一直去工作队列里获取任务,非核心线程已经满了,则会workQueue.take()核心线程去获取任务,前面的runWorker方法是有while循环的,这样就会一直执行下去,循环拿取任务,如果这个时候工作队列里面没有队列,超过keepAliveTime线程存活时间还没有拿到任务,则会对对应线程进行销毁。private Runnable getTask() {     boolean timedOut = false; // Did the last poll() time out?      for (;;) {         int c = ctl.get();         int rs = runStateOf(c);          // Check if queue empty only if necessary.         if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {             decrementWorkerCount();             return null;         }          int wc = workerCountOf(c);          // Are workers subject to culling?         boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;          if ((wc > maximumPoolSize || (timed && timedOut))             && (wc > 1 || workQueue.isEmpty())) {             if (compareAndDecrementWorkerCount(c))                 return null;             continue;         }          try {             Runnable r = timed ?                 workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :                 workQueue.take();             if (r != null)                 return r;             timedOut = true;         } catch (InterruptedException retry) {             timedOut = false;         }     } }  复制代码总结
  在日常开发中,对线程池的优化也是比较重要的,如果线程池的核心线程数和最大线程数都不是随意定义的,还是要结合本身服务器cpu的情况,以及阻塞队列的使用,在一定情况下能缓解线程的压力,本身阻塞队列是带有阻塞和唤醒的功能,阻塞队列的长度也是需要根据实际开大的业务场景去定义的,最后运用好线程池,在处理高并发的业务场景下还是尤为关键的一项技术。

全国冬季两项冠军赛圆满收官内蒙古斩获混合接力金牌今天(25日)上午,20222023全国冬季两项冠军赛在甘肃省白银市收官。在赛事最后一个项目混合接力赛中,内蒙古自治区冬季运动中心代表队的丁雨欢杨连红胡伟耀谷仓以1小时25分47秒1923年的内蒙古阿拉善,苍天般的阿拉善辽阔而神奇今天要和大家一家分享的是一组拍摄于1923年的内蒙古阿拉善老城的老照片。在看照片之前,让我们先了解一下阿拉善,阿拉善位于内蒙古最西部,阿拉善系蒙古语,意为五彩斑斓之地,阿拉善是贺兰神奇的天府穴,肺气的聚集的门户,中医调畅肺气治疗气喘的穴位所见所得,都很科学今天和大家聊一下天府穴。这个属于肺经的天府穴是肺经经气聚结的部位,中医认为它是调畅肺气的要穴,多用于治疗气喘气促,这真的有这样的功效吗?下面和大家聊聊这个问题。首日军魔头我杀死了牟高轩校长,为了显摆还展示了高超的砍头技术鹿田正夫,1918年出生在岛根县的一个村庄,他父亲是教师,也是个狂热的天皇崇拜者,他上学后又系统地接受了军国主义思想的熏陶。侵略战争开始后,他渴望在中国干出一番事业,上可效忠天皇,联发科将在MWC2023展示卫星通信技术为智能手机提供双向卫星通信功能据之前报道,三星宣布已掌握标准化5G非地面网络技术,将用于智能手机和卫星之间的直接通信,并计划将这项技术整合到Exynos调制解调器解决方案中,加速5G卫星通信的商业化。联发科在手国产手机技术和国外手机技术的差距在哪?处理器国产手机中常用的处理器芯片主要来自美国的高通台湾的联发科和中国的华为海思等公司。其中,华为海思是国内自主研发的处理器芯片品牌,已经推出了多款高性能的芯片,例如麒麟系列芯片,被两个消息传来华为越压越强,拜登失算华为虽然是一家企业,但是却在承受远远超出常规企业的压力和竞争。作为国内无容置疑的技术和创新先锋,从多年前就开始被美方找各种理由的压制,好在华为承受住了四轮非常严苛的制裁。从这个角度闽都创新实验室3年多突破卡脖子技术40多项突破关键核心技术和制约产业发展卡脖子技术40多项,完成重大创新成果超25项,建设10个高能级研发支撑平台,与120多家省内外龙头骨干企业深入接洽首批四家福建省创新实验室之一中国福建男篮奇兵出炉!吴前砍18433,得分全队第一,媒体人英雄本色世预赛中国男篮对阵伊朗,上半场中国男篮状态不佳,防守端被伊朗轰下46分,反观中国男篮自家进攻不佳,半场三分11中3,导致打完上半场还处于落后。不过下半场中国男篮及时调整,CBA常规粤港澳大湾区数字金融发展报告建议从技术货币和制度三方面扩展互联互通本报记者郝亚娟张荣旺上海北京报道粤港澳大湾区金融开放又添创新举措。近日,中国人民银行通过官微发布消息称,央行银保监会等多部门加大金融支持横琴前海建设力度。央行副行长外汇局局长潘功胜东方电热预镀镍需求放量的总体方向是明确的e公司讯,东方电热(300217)近日接受机构调研时表示,锂电池材料方面,主要产品是预镀镍材料。2万吨募投项目预镀镍工序已建成并试车成功。2023年,公司出货量内部目标为1。52万
扬舒特云亮相海南岛国际电影节大师班畅谈电影创作与教育新海南客户端南海网南国都市报12月21日消息(记者符彩云)12月21日,国际知名电影教育家和电影导演扬舒特云亮相第四届海南岛国际电影节大师班。他通过视频连线,从专业视角和行业经验出手把手教你一套完善且高效的k8s离线部署方案作者郝建伟背景面对更多项目现场交付,偶而会遇到客户环境不具备公网条件,完全内网部署,这就需要有一套完善且高效的离线部署方案。系统资源编号主机名称IP资源类型CPU内存磁盘01hrk造车新势力直面淘汰赛新能源汽车在今年整体保持高速增长。自主品牌新能源车崭露头角。消费者对于新能源车的消费习惯也正在发生变化。新势力的高光时刻正在逝去。从数据上看,新能源汽车在2022年继续保持高速增长年末47K新机推荐,优点都给你标记了!按需选择不怕掉坑年底了,又到了该换机的时候了,今年年底确实有不少好手机值得入手,而且每一款上市的产品都有自己优势,如果你打算年底换机的话,不妨来看看本文推荐的这几款,根据自己的需求按需购入即可。1AI创作浪潮汹涌,布局两年多的昆仑万维站上风口?如何用AIGC支点,撬动元宇宙生态?作者孙佳编辑丨高岩来源野马财经被AI的绘画技术整破防了AI会取代人类绘画吗这些近期挂在微博热搜榜上的话题,揭示了AI绘画的火爆程度。无论是自拍合如果伊隆马斯克卸任Twitter首席执行官,狗狗币会下跌吗?特斯拉首席执行官兼Twitter所有者埃隆马斯克在社交媒体平台上进行了一项民意调查,询问人们他是否应该辞去这家科技公司的负责人一职。作为狗狗币(DOGE)的支持者,这种流行的代币随隔夜美股三大指数四连阴汽车板块普跌小鹏跌超612月19日美东时间周一,投资者对经济衰退的担忧加剧,三大股指连续第四个交易日集体收跌,纳指跌超1。截至收盘,道琼斯指数跌0。49,报32,757。54点标普500指数跌0。90,走进张家界黄龙洞,看保价1个亿的定海神针黄龙洞是张家界的核心景观,1983年被发现,1984年10月1日正式对外开放。黄龙洞属典型的喀斯特岩溶地貌,洞内空间庞大,已探明洞底总面积超过了10万平方米,全长7。5公里,垂直高C罗女友晒纹身表爱意,却被网友骂炫富,无视流言蜚语继续发美照乔治娜自与足球巨星C罗谈恋爱后身价暴涨,从名店售货员摇身一变,成为收藏限量版奢侈品的名人,早前更在纪录片IAmGeorgina公开超奢侈生活模式。经历了丧子之痛后,乔治娜重新出发,李亚鹏妻子晒一家三口合影,首次公开女儿高清正脸,长得像李亚鹏12月5日晚,李亚鹏的妻子海哈金喜在社交平台上晒出一家三口合影,这也是她当妈妈后首次公开女儿未打码高清正脸,看到她罕见秀恩爱,不少网友聚集到她评论区,夸宝宝长得非常可爱。海哈金喜的金钱的香气明星扎堆做潮牌只为割韭菜欧阳娜娜最近大范围翻车。原因无他。自己的品牌nabi将一件浴袍买到了988,高定价击碎了无数nabi女孩的梦。这几年越来越多的明星开始入局潮牌,鹿晗陈伟霆王嘉尔杨超越,为什么明星们