精华内容
下载资源
问答
  • 线程池

    万次阅读 2019-06-23 21:13:32
    什么要使用线程池? 线程是处理器调度的基本单位。我们会每一个请求都独立创建一个线程,而操作系统创建线程、切换线程状态、结束线程都要使用CPU进行调度。使用线程池能够更好对线程进行管理、复用等。 JDK...

    线程池

    在这里插入图片描述

    为什么要使用线程池?
    线程是处理器调度的基本单位。我们会为每一个请求都独立创建一个线程,而操作系统创建线程、切换线程状态、结束线程都要使用CPU进行调度。使用线程池能够更好对线程进行管理、复用等。

    JDK为我们提供了那些支持?
    ScheduledThreadPoolExecutor
    ThreadPoolExecutor(最核心)
    ForkJoin Pool

    ThreadPoolExecutor的结构
    在这里插入图片描述
    核心属性:
    corePoolSize #核心线程数
    maxinmumPoolSize #线程总数 非核心数=总数-核心数
    keepAliveTime #当前线程数大于核心线程数时 非核心线程的等待被执行的等待时间
    TimeUnit unit #时间单位
    workQueue #保存未被执行的任务队列
    RejectedExecutionHandler #拒绝处理器

    poolExecutor 线程池对象
    submit(Callable x) execute(Runnable x) 将任务送入到任务队列
    Runnable接口没有返回值,Callable有返回值
    核心:
    当前运行线程数 小于corePoolSize 任务直接交给核心线程进行执行(通过线程调度执行任务)
    当前运行线程数 大于或等于 corePoolSize 任务且满足队列规则 任务将进入任务队列进行等待
    当前运行线程数 大于或等于 corePoolSize 任务且不满足队列规则 任务进入非核心线程(这类线程有存活时间,不一定会执行成功)

    任务队列(实现BlockingQueue接口)
    SyschronousQueue:每一次add()插入 必须要等待相对删除/读取操作
    ArrayBlockingQueue:数组的方式,大小创建后不能改变大小,具有阻塞特性。
    LinkedBlockingQueue:无限容量 基于链表的形式
    LinkedBlockingDeque :无限双端链表队列,可以从两头进行元素的读/取操作
    PriorityBlockingQueue:按照优先级进行内部元素排序的无限队列。
    LinkedTransferQueue:无限队列,先进先出,具有阻塞特性。
    #阻塞特性:当队列满了,便会阻塞等待,直到有元素出队,后续的元素才可以被加入队列。

    拒绝处理器
    适用:那些既不能进入核心线程、等待队列,也无法创建新的线程执行(即非核心线程),或者线程异常等。
    CallerRunsPolicy:直接运行该任务的run方法,但不是在线程池内部
    AbortPolicy:RejectedExecutionException异常抛出(默认)
    DiscardPolicy:不会做任何处理
    DiscardOldestPolicy:检查等待队列 强行取出队列头部任务 进行执行

    ForkJoin框架

    在这里插入图片描述
    ForkJoin采用“工作窃取模式”,当有新的任务它可以将其拆分成更小的任务去执行,之后将结果进行合并,得到最终的结果。这种思想,类似于map/reduce的分而治之的思想处理任务。

    ForJoin的简单实现

    ForkJoinPool forkJoinPool = new ForkJoinPool();//实现ForkJoin 就必须有ForkJoinPool的支持
    ForkJoinTask<Long> task = new ForkJoinWork(0L,10000000000L);//参数为起始值与结束值
    Long invoke = forkJoinPool.invoke(task);#执行ForkJoin任务中的compute()
    

    ForJoinTask必须继承RecursiveTask(有返回值)或者 RecursiveAction (没有返回值)

    public class ForkJoinWork extends RecursiveTask<Long> {
        private Long start;//起始值
        private Long end;//结束值
        public static final  Long critical = 100000L;//临界值
        public ForkJoinWork(Long start, Long end) {
            this.start = start;
            this.end = end;
        }
    
    @Override
    protected Long compute() {
        //判断是否是拆分完毕
        Long lenth = end - start;
        if(lenth<=critical){
            //如果拆分完毕就相加
            Long sum = 0L;
            for (Long i = start;i<=end;i++){
                sum += i;
            }
            return sum;
        }else {
            //没有拆分完毕就开始拆分
            Long middle = (end + start)/2;//计算的两个值的中间值
            ForkJoinWork right = new ForkJoinWork(start,middle);
            right.fork();//拆分,并压入线程队列
            ForkJoinWork left = new ForkJoinWork(middle+1,end);
            left.fork();//拆分,并压入线程队列
    
            //合并
            return right.join() + left.join();
        }
    }
    }
    

    在这里插入图片描述

    展开全文
  • 线程池管理(1)-什么需要线程池

    千次阅读 2019-05-04 15:51:46
    什么需要线程池呢,没想明白这个问题,看再多线程池的源码都没有用,先要知道线程池技术解决了什么问题,才能看的懂源码。因为所有的代码都是为了解决问题 问题 抛几个问题,看看你是否知道,不知道的话,可能你对...

    摘要

    为什么需要线程池呢,没想明白这个问题,看再多线程池的源码都没有用,先要知道线程池技术解决了什么问题,才能看的懂源码,因为所有的代码都是为了解决实际的工程问题。

    问题

    抛几个问题,看看你是否知道,不知道的话,可能你对线程池的理解还不够深入,还是一知半解。那么本文会对你有用,请继续看下去

    • 线程池的线程数可以为1吗?
    • 线程数为1的线程池有存在的必要吗
    • 2个有5个核心线程的线程池和1个有10个核心线程的线程池有什么区别
    • 一个应用中如何管理线程池
    • 线程池池化技术和消息队列有什么区别

    线程池原理

    在大学里我们学习c语言时,一个main函数写到底,就可以交作业了。刚开始工作时,mvc一路controller -> service -> dao就OK了。但是工作中写代码是要解决实际问题的。你啪啪啪写完了代码,用户发现你这个接口响应太慢了,怎么办?

    在这里插入图片描述
    用户提交任务到程序执行完成,大致的过程如上图,提交一个task,然后有个线程去执行。
    所以要提高​程序执行的效率可以从两个方面来考虑

    1. 异步,先响应,返回中间结果,然后异步处理,将结果返回
    2. 并发,多个线程来执行。

    本篇说的线程池主要就是从1的维度来提高程序执行的效率

    生产者消费者模式

    有一定工作经验的朋友对消息队列的削峰填谷,系统解耦肯定不陌生。那么线程池,算不算削峰填谷呢?
    异步化后,相当于把所有的task放在了队列中。也就是生产者 -> 容器 -> 消费者。如下图
    在这里插入图片描述
    从图可以看出,线程池技术使系统复杂了,也提供了更多的灵活性。通过队列的形式,我们将任务的执行拆分成了生产者,消费者模式。每一步只用关心自己的事情。如果我们的任务很复杂,我们可以将任务拆分成不同的步骤,每一步骤可以使用不同的线程池来解决,以此来提高效率。

    可管理性

    看上去通过线程池完美解决了我们的问题,那么需要付出什么代价呢?cpu的资源是有限的,线程的创建也需要代价,我们一个java应用进程的资源是毕竟是有限的。我们不可能在应用中无限的创建线程池。所以我们需要管理线程池。

    通常,对于简单的应用,我们使用一个单例线程池即可,让应用中的所有task都使用同一个线程池,防止一些初级程序员在应用中随意创建线程池,导致线程资源吃紧,线程占用过多的资源。

    当应用中task比较复杂的时候,我们就需要使用分治的思想,对线程池进行隔离。
    比如有些是cpu密集型的,有些是IO密集型的;任务的重要程度也有轻重之分;任务的执行时间也有不同。我们需要对为这些任务建立不同的线程池,以此来提高效率。

    总结

    线程池是一种异步化技术,通过预先创建线程/异步处理来提高响应速度。同时通过统一调配线程资源,可以降低线程的重复创建问题,提高线程的利用率,中心化管理有利于对资源的有效控制,防止滥用。

    关注【方丈的寺院】,第一时间收到文章的更新,与方丈一起开始技术修行之路
    在这里插入图片描述

    展开全文
  • 并发编程经历:线程池的使用

    万次阅读 多人点赞 2019-07-31 18:38:24
    线程池的使用 使用线程池管理线程可以最大程度的利用线程,节省资源消耗,它通过利用已有的线程多次循环执行多个任务从而提高系统的处理能力。 我们可以通过java.util.concurrent.ThreadPoolExecutor类来创建线程池...

    线程池的使用

    使用线程池管理线程可以最大程度的利用线程,节省资源消耗,它通过利用已有的线程多次循环执行多个任务从而提高系统的处理能力。

    我们可以通过java.util.concurrent.ThreadPoolExecutor类来创建线程池,一个任务通过 execute(Runnable)方法被添加到线程池,任务就是一个 Runnable类型的对象,任务的执行方法就是Runnable类型对象的run()方法。

    下面介绍一下里面的一些参数。

    1、创建一个线程池需要输入几个参数:

    ·        corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。

    ·        runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。 可以选择以下几个阻塞队列。

    o   ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。

    o   LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

    o   SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。

    o   PriorityBlockingQueue:一个具有优先级的无限阻塞队列。

    ·        maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。

    ·        ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

    ·        RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。

    o   AbortPolicy:直接抛出异常。

    o   CallerRunsPolicy:只用调用者所在线程来运行任务。

    o   DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。

    o   DiscardPolicy:不处理,丢弃掉。

    o   当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。

    ·        keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。

    ·        TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),秒(SECONDS),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

    2、当一个任务通过execute(Runnable)方法欲添加到线程池时,会有如下几种情况:

    ·         如果此时线程池中的数量小于corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。

    ·        如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列。

    ·        如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。

    ·        如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。

    ·        当线程池中的线程数量大于 corePoolSize时,如果某线程空闲时间超过keepAliveTime,线程将被终止。这样,线程池可以动态的调整池中的线程数。

    3、举一个简单的例子:

    创建 TestThreadPool 类:

    1.  importjava.util.concurrent.ArrayBlockingQueue; 

    2.  importjava.util.concurrent.ThreadPoolExecutor; 

    3.  import java.util.concurrent.TimeUnit; 

    4.   

    5.  public class TestThreadPool { 

    6.    

    7.      private static int produceTaskSleepTime =2; 

    8.        

    9.      private static int produceTaskMaxNumber = 2; 

    10.   

    11.     public static void main(String[] args){ 

    12.   

    13.         // 构造一个线程池 

    14.         ThreadPoolExecutor threadPool = newThreadPoolExecutor(2, 4, 3, 

    15.                 TimeUnit.SECONDS, newArrayBlockingQueue<Runnable>(3), 

    16.                 newThreadPoolExecutor.DiscardOldestPolicy()); 

    17.   

    18.         for (int i = 1; i <=produceTaskMaxNumber; i++) { 

    19.             try { 

    20.                 String task = "task@" + i; 

    21.                 System.out.println("创建任务并提交到线程池中:" +task); 

    22.                 threadPool.execute(newThreadPoolTask(task)); 

    23.   

    24.                 Thread.sleep(produceTaskSleepTime); 

    25.             } catch (Exception e) { 

    26.                 e.printStackTrace(); 

    27.             } 

    28.         } 

    29.     } 

    30.  }  

    创建 ThreadPoolTask类:

    31. public class ThreadPoolTask implementsRunnable, Serializable { 

    32.   

    33.     private Object attachData; 

    34.   

    35.     ThreadPoolTask(Object tasks) { 

    36.         this.attachData = tasks; 

    37.     } 

    38.   

    39.     public void run() { 

    40.           

    41.         System.out.println("开始执行任务:" +attachData); 

    42.           

    43.         attachData = null; 

    44.     } 

    45.   

    46.     public Object getTask() { 

    47.         return this.attachData; 

    48.     } 

    49.  }  

    执行结果:

    创建任务并提交到线程池中:task@ 1

    开始执行任务:task@ 1

    创建任务并提交到线程池中:task@ 2

    开始执行任务:task@ 2

     4、再讲一个实际的例子

    这里用的是spring的线程池:org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor。

    直接上代码:

    50.     //是否中断导入数据程序

    51.     publicstatic AtomicBoolean  terminateImport = newAtomicBoolean(false);

    52.     //成功条数

    53.     public static AtomicLong success_line = newAtomicLong();

    54.     //失败条数

    55.     publicstatic AtomicLong error_line = new AtomicLong();

    56.     //是否发现有线程rejected,如果有,说明线程队列满了,外部执行代码暂时中断队列填充,等待5s后,重新填充.

    57.     publicstatic AtomicBoolean found_rejected = new AtomicBoolean(false);

    58.     //开始执行

    59.     publicvoid startSwitch(int itemsPerPage, String updateMode,String applySeqno, Date startDate,Date endDate) {

    60.         int nowPage = 1;

    61.         int exec_sum = 0 ;

    62.         boolean hasNext = true ;

    63.         //重置静态值

    64.         success_line = new AtomicLong(0L);

    65.         error_line = new AtomicLong(0L);

    66.         terminateImport = new AtomicBoolean(false);

    67.  

    68.         ThreadPoolTaskExecutor threadPoolTaskExecutor= new ThreadPoolTaskExecutor();

    69.         threadPoolTaskExecutor.setCorePoolSize(100);

    70.         threadPoolTaskExecutor.setMaxPoolSize(200);

    71.         threadPoolTaskExecutor.setQueueCapacity(100);

    72.         threadPoolTaskExecutor.setRejectedExecutionHandler(newRejectedExecutionHandler() {

    73.             @Override

    74.             public voidrejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {

    75.                 logger.warn("findRejectedExecutionException error !!,will set found_rejected boolean is false");

    76.                 found_rejected.set(true);

    77.                 threadPoolExecutor.execute(runnable);

    78.             }

    79.         });

    80.         //设成true后当调用shutdown()关闭线程池时会去检查任务是否都执行完毕

    81.         threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);

    82.         threadPoolTaskExecutor.initialize();

    83.  

    84.         while (hasNext) {

    85.             …

    86.             // applyDTOs是调接口进行分页查询得到的List集合,就是上面”…”省略的部分

    87.             //如果当次取出的总数比分页数还要小,那么下次进来直接中断掉这个循环

    88.             if(itemsPerPage>applyDTOs.size()){

    89.                 hasNext = false ;

    90.             }

    91.             if(ListUtil.isNotBlank(applyDTOs)){

    92.                 if(found_rejected.get()==false){

    93.                     if(ApplyInfoSync.terminateImport.get()==false){

    94.                         ApplySyncDataThread applySyncDataThread= new ApplySyncDataThread(

    95.                                 convert2LoanApplyInfoDOList(applyDTOs),updateMode, loanApplyComponent);

    96.                         threadPoolTaskExecutor.execute(applySyncDataThread);

    97.                     }else{

    98.                         hasNext= false;

    99.                         LogUtil.warn(logger, "主线程发现中断,开始尝试关闭线程池新进入数据");

    100.                      }

    101.                  }else{

    102.                      LogUtil.warn(logger,"执行被拒绝,队列已满了,需要等待5秒");

    103.                      try {

    104.                          TimeUnit.MILLISECONDS.sleep(5000L);

    105.                          found_rejected.set(false);

    106.                      } catch(InterruptedException e) {

    107.                          LogUtil.warn(e,logger,"foundrejected thread,Thread Sleep is error !!");

    108.                      }

    109.                  }

    110.              }

    111.              exec_sum= exec_sum+applyDTOs.size();

    112.              if(hasNext)

    113.                  nowPage++;

    114.          }

    115.   

    116.          while (threadPoolTaskExecutor.getActiveCount()>0){

    117.              try {

    118.                  logger.warn("threadPool ishave active count ,now sleep...");

    119.                  TimeUnit.MILLISECONDS.sleep(60000L);

    120.              } catch (InterruptedException e) {

    121.                  logger.warn("Thread Sleepis  error !!", e);

    122.              }

    123.          }

    124.          threadPoolTaskExecutor.shutdown();

    125.   

    126.          //检查线程池是否完全关闭,否则先等一等再走到日志打印阶段

    127.          while (threadPoolTaskExecutor.getThreadPoolExecutor().isTerminated()== false) {

    128.              try {

    129.                  TimeUnit.MILLISECONDS.sleep(6000L);

    130.              } catch (InterruptedException e) {

    131.                  LogUtil.error(e,logger,"ThreadSleep is  error !!");

    132.              }

    133.          }

    134.        …//一些打印日志的操作

    135.      }

    这里其他的不多说了,就说几点使容易看得懂。我这里有两个属性:terminateImport和found_rejected,他们都是AtomicBoolean类型(传入的boolean变量会被转换为volatile的int值,true为1,false为0)的都被static修饰,所以都只有一份且是同步安全的。terminateImport在一开始调用startSwitch时被重置为false,表明没有被中断,当在执行的过程中,有其他的入口调用terminateImport.set(true)后,程序再执行到if(ApplyInfoSync.terminateImport.get()==false)就会是false的,从而达到中断的作用;found_rejected用来标记任务是否被拒绝,经过之前的对线程池的介绍,应该知道了当达到最大线程数,任务队列也满了的时候,再execute的任务会被拒绝,所以我在threadPoolTaskExecutor.setRejectedExecutionHandler(…)设置饱和策略时自己定义实现了一个RejectedExecutionHandler接口来自定义策略,在里面把found_rejected标记改为了true,这样当程序再次执行到if(found_rejected.get()==false)就会是false的,从而可以监视线程和队列是否已经满了,当满了的时候,我就等待5秒,然后把found_rejected标记改为了false就可以继续填充队列了,至于里面为什么还要执行一次threadPoolExecutor.execute(runnable);是因为如果不执行被拒绝的任务,那任务就被抛弃了,当然你也可以做其他操作,例如持久化任务(就是存入数据库)等。

    展开全文
  • java基础之线程池为什么要使用线程池为什么不使用自动创建的线程池ThreadPoolExecutor 的核心参数 为什么要使用线程池 第一点,反复创建线程系统开销比较大,每个线程创建和销毁都需要时间,如果任务比较简单,那么...

    为什么要使用线程池

    第一点,反复创建线程系统开销比较大,每个线程创建和销毁都需要时间,如果任务比较简单,那么就有可能导致创建和销毁线程消耗的资源比线程执行任务本身消耗的资源还要大。
    第二点,过多的线程会占用过多的内存等资源,还会带来过多的上下文切换,同时还会导致系统的不稳定。

    为什么不使用自动创建的线程池

    FixedThreadPool 和 SingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
    在这里插入图片描述
    CachedThreadPool 和 ScheduledThreadPool:允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
    在这里插入图片描述

    ThreadPoolExecutor 的核心参数

    在这里插入图片描述
    第 1 个参数:corePoolSize 表示线程池的常驻核心线程数。如果设置为 0,则表示在没有任何任务时,销毁线程池;如果大于 0,即使没有任务时也会保证线程池的线程数量等于此值。但需要注意,此值如果设置的比较小,则会频繁的创建和销毁线程;如果设置的比较大,则会浪费系统资源,所以开发者需要根据自己的实际业务来调整此值。

    第 2 个参数:maximumPoolSize 表示线程池在任务最多时,最大可以创建的线程数。官方规定此值必须大于 0,也必须大于等于 corePoolSize,此值只有在任务比较多,且不能存放在任务队列时,才会用到。

    第 3 个参数:keepAliveTime 表示线程的存活时间,当线程池空闲时并且超过了此时间,多余的线程就会销毁,直到线程池中的线程数量销毁的等于 corePoolSize 为止,如果 maximumPoolSize 等于 corePoolSize,那么线程池在空闲的时候也不会销毁任何线程。

    第 4 个参数:unit 表示存活时间的单位,它是配合 keepAliveTime 参数共同使用的。

    第 5 个参数:workQueue 表示线程池执行的任务队列,当线程池的所有线程都在处理任务时,如果来了新任务就会缓存到此任务队列中排队等待执行。

    展开全文
  • 什么有线程池的出现?2. 线程池的继承关系3. 线程池的底层原理4.线程池的创建与使用4.1 手工创建线程池4.2 向线程池提交任务4.2.1 execute()方法4.2.2 submit()方法5.JDK内置的4大线程池5.1 普通调度池5.1.1 无...
  • java 什么是线程池什么要使用线程池
  • 1. 什么需要线程池?  多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。   假设一个服务器完成一项任务所需时间:T1 创建线程时间,T2 ...
  • 线程池之四大线程池

    2019-11-27 22:18:58
    文章目录线程池之四大线程池线程池的基本内容1、四大线程池2、线程池的本质3、线程池在刚创建的时候有几个线程?4、什么时候才会有线程?5、如果核心线程数是10 ,最大线程数20。但我们提交第11个任务时,线程池会...
  • Java 多线程:彻底搞懂线程池

    万次阅读 多人点赞 2019-07-09 19:27:00
    1 线程池的优势 2 线程池的使用 3 线程池的工作原理 4 线程池的参数 4.1 任务队列(workQueue) 4.2 线程工厂(threadFactory) 4.3 拒绝策略(handler) 5 功能线程池 5.1 定长线程池(FixedThreadP...
  • 什么要线程池?怎么使用线程池

    千次阅读 2019-07-28 22:12:20
    文章目录一、什么要使用线程池?(一)提高程序的执行效率(二)控制线程的数量,防止程序崩溃二、怎么使用线程池(一)使用线程池的一些常用的方法1.newCachedThreadPool2.newFixedThreadPool3....
  • Java线程池详解

    万次阅读 多人点赞 2018-04-08 19:07:23
    1.什么需要线程池? java中经常需要用到多线程来处理一些业务,我们非常不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的...
  • 线程池总结

    万次阅读 2021-04-16 11:10:55
    1、什么时候使用线程池? 单个任务处理时间比较短 需要处理的任务数量很大 2、线程池优势 重用存在的线程、减少线程创建、消亡的开销、提高性能 提高响应速度 提高线程的可管理性 3、线程池重要属性 ctl:记录...
  • Netty 线程池

    万次阅读 2021-08-09 09:49:58
    Netty的线程池有什么样的特性 Java 原生线程池 Java 原生的线程池主要有三种:ThreadPoolExecutor、ScheduledThreadPoolExecutor、ForkJoinPool。 ThreadPoolExecutor 是最古老的类,我们通常说的线程池,也是指这...
  • Java线程池七个参数详解

    万次阅读 多人点赞 2019-04-23 11:14:33
    java多线程开发时,常常用到线程池技术,这篇文章是对创建java线程池时的七个参数的详细解释。 从源码中可以看出,线程池的构造函数有7个参数,分别是corePoolSize、maximumPoolSize、keepAliveTime、unit、...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 292,641
精华内容 117,056
关键字:

线程池为1