千家信息网

Java中的线程池有什么用

发表于:2024-11-19 作者:千家信息网编辑
千家信息网最后更新 2024年11月19日,这篇文章主要讲解了"Java中的线程池有什么用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Java中的线程池有什么用"吧!Java中的线程池【1】使
千家信息网最后更新 2024年11月19日Java中的线程池有什么用

这篇文章主要讲解了"Java中的线程池有什么用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Java中的线程池有什么用"吧!

Java中的线程池

【1】使用线程池的好处:

1)降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗。2)提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行。3)提高线程的可管理性。线程池可以进行统一分配、调优和监控线程。

【2】构造方法:

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler);参数说明:        1)corePoolSize:核心池的大小。                        1)在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务。                2)默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务。                        注意:即使其它空闲的线程能够执行新任务也会去创建线程,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中。                3)调用prestartAllCoreThreads()或prestartCoreThread()方法来预创建线程,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。                                        2)workQueue:任务缓存队列,是一个阻塞队列,用来存储等待执行的任务;类型为BlockingQueue,通常可以取下面4种类型:                        1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;                2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQueue。                        eg:静态工厂方法Executors.newFixedThreadPool()就是使用的这个队列。                3)SynchronousQueue:这个队列不会保存提交的任务,而是直接新建一个线程来执行新来的任务。                        说明:每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue。                        eg:静态工厂方法Executors.newCachedThreadPool使用的就是这个队列。                4)PriorityBlockingQueue:一个具有优先级的无限阻塞队列。                                说明:                        1>一般使用LinkedBlockingQueue和SynchronousQueue                        2>建议使用有界队列,有界队列能增加系统的稳定性。                                eg:如果线程池里的工作线程全部阻塞,任务积压在线程池里,如果设置成无界队列,那么这个队列会越来越大,有可能会撑满内存,导致整个系统不可用。                        3)maximumPoolSize:线程池中允许创建的最大线程数。                        1)如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程来执行任务。                2)如果使用了无界的任务队列,则这个参数就不起什么作用了(队列默认的大小是:Integer.MAX_VALUE,在队列未满之前,线程池是不会再去创建新线程了)。                        4)RejectedExecutionHandler:任务拒绝策略,当任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:                        1)ThreadPoolExecutor.AbortPolicy:               丢弃任务并抛出RejectedExecutionException异常,默认使用该策略。                2)ThreadPoolExecutor.DiscardPolicy:     丢弃任务,但是不抛出异常;会导致被丢弃的任务无法再次被执行                3)ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程);会导致被丢弃的任务无法再次被执行                4)ThreadPoolExecutor.CallerRunsPolicy:  由调用线程处理该任务;主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度                 说明:也可以实现RejectedExecutionHandler接口来自定义策略。        5)keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。                        默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用。                但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;                                        6)TimeUnit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:                        TimeUnit.DAYS;                          天                TimeUnit.HOURS;                         小时                TimeUnit.MINUTES;                       分钟                TimeUnit.SECONDS;                       秒                TimeUnit.MILLISECONDS;          毫秒                TimeUnit.MICROSECONDS;          微妙                TimeUnit.NANOSECONDS;           纳秒                        7)ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。

【3】其它方法:

任务的提交:        execute(Runnable command): 提交后没有返回值,故无法判断任务是否被线程池执行成功。                        submit():       提交后返回一个Future对象,通过这个future对象可以判断任务是否执行成功。                通过future的get()方法来获取返回值,该方法会阻塞当前线程直到任务完成。                get(long timeout, TimeUnit unit)方法:阻塞当前线程一段时间后立即返回,这时候任务可能没有执行完。线程池容量的动态调整:        setCorePoolSize()               设置核心池的大小        setMaximumPoolSize()    设置线程池最大能创建的线程数线程池的关闭:        原理:遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。                shutdown()                              1>将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。                2>不再接受新的任务,但是不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止。        shutdownNow()                   1>首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并且清空任务缓存队列,并返回等待执行任务的列表.        说明:                1)只要调用了这两个关闭方法中的任意一个,isShutdown方法就会返回true。                2)当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。

【4】线程池的状态:

// RUNNING状态:线程池正常运行,可以接受新的任务并处理队列中的任务private static final int RUNNING    = -1 << COUNT_BITS;// SHUTDOWN状态:不再接受新任务,但是会执行队列中的任务private static final int SHUTDOWN   =  0 << COUNT_BITS;// STOP状态:不再接受新任务,不处理队列中的任务,中断正在处理的任务private static final int STOP       =  1 << COUNT_BITS;// 过渡状态:所有的任务都执行完了,线程池已经没有有效的线程了,此时线程池的状态为过渡状态,并且将要调用terminated()方法private static final int TIDYING    =  2 << COUNT_BITS;// 终止状态:terminated()方法调用完成后的状态private static final int TERMINATED =  3 << COUNT_BITS;1>当线程池刚创建后,线程池处于RUNNING状态,可以接受新的任务并处理队列中的任务2>如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;3>如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;4>当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。

【5】线程池的处理流程:

ThreadPoolExecutor执行execute方法分下面4种情况。        1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步骤需要获取全局锁)。        2)如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。        3)如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(注意,执行这一步骤需要获取全局锁)。        4)如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用  RejectedExecutionHandler.rejectedExecution()方法。

感谢各位的阅读,以上就是"Java中的线程池有什么用"的内容了,经过本文的学习后,相信大家对Java中的线程池有什么用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

0