服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 一篇文章带你了解Java中ThreadPool线程池

一篇文章带你了解Java中ThreadPool线程池

2021-11-25 13:37Tttori Java教程

线程池可以控制运行的线程数量,本文就线程池做了详细的介绍,需要了解的小伙伴可以参考一下

threadpool

线程池的优势

线程池做的工作主要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出的线程排队等候,等待其他线程执行完毕,再从队列中取出任务来执行

线程池的特点

线程复用、控制最大并发数、管理线程

  • 降低资源消耗。重复利用已创建的线程,降低创建和销毁线程的开销
  • 提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立刻执行
  • 提高线程的可管理性。使用线程池可以对线程进行统一的分配、调优和监控

 

1 线程池的方法

执行长期任务性能好,创建一个线程池,一池有n个固定的线程,可以控制线程最大并发数,有固定线程数的线程池[

?
1
executorservice threadpool = executors.newfixedthreadpool(n);

单个任务执行,它只会使用单个工作线程,一池一线程

?
1
executorservice threadpool = executors.newsinglethreadexecutor();

执行短期异步任务,可缓存线程池,线程池根据需要创建新线程,但在先前构造的线程可以复用,也可灵活回收空闲的线程,可扩容的池

?
1
executorservice threadpool = executors.newcachedthreadpool();

周期性线程池;支持定时及周期性任务执行

?
1
executorservice threadpool = executors.newscheduledthreadpool();

(1) newfixedthreadpool

可以控制线程最大并发数的线程池:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class fixedthreadpool {
 
    private static atomicinteger num = new atomicinteger(0);
 
    private static executorservice executorservice = executors.newfixedthreadpool(2);
 
    public static void main(string[] args) {
        countsum c= new countsum();
        //将coutsum作为task,submit至线程池
        for (int i = 0; i < 2; i++) {
            executorservice.submit(c);
        }
        //task执行完成后关闭
        executorservice.shutdown();
    }
 
    static class countsum implements runnable{
        @override
        public void run() {
            for (int i = 0; i < 500; i++) {
                try{
                    system.out.println("thread - "+thread.currentthread().getname()+" count= "+ num.getandincrement());
                    thread.sleep(100);
                }catch (exception e){
                    e.printstacktrace();
                }
            }
        }
    }
}

结果:

一篇文章带你了解Java中ThreadPool线程池

(2) newsinglethreadexecutor

只会使用唯一的工作线程执行任务的线程池:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class singlethreadexecutor {
 
    private static atomicinteger num = new atomicinteger(0);
 
    private static executorservice executorservice = executors.newsinglethreadexecutor();
 
    public static void main(string[] args) {
        //将coutsum作为task,submit至线程池
        for (int i = 0; i < 2; i++) {
            executorservice.submit(new countsum());
        }
        //task执行完成后关闭
        executorservice.shutdown();
    }
 
    static class countsum implements runnable{
        @override
        public void run() {
            for (int i = 0; i < 500; i++) {
                try{
                    system.out.println("thread - "+thread.currentthread().getname()+" count= "+ num.getandincrement());
                    thread.sleep(100);
                }catch (exception e){
                    e.printstacktrace();
                }
            }
        }
    }
}

结果:

一篇文章带你了解Java中ThreadPool线程池

(3) newscheduledthreadpool

传参值为corepoolsize大小,支持定时及周期性任务执行

延期执行示例:调用schedule方法,三个参数:task,delay,timeunit

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class scheduledthreadpool {
    // corepoolsize = 2
    private static scheduledexecutorservice service = executors.newscheduledthreadpool(2);
 
    public static void main(string[] args) {
        system.out.println("thread - "+thread.currentthread().getname()+" begin "+ new date());
 
        service.schedule(new print(),5, timeunit.seconds);
 
        service.shutdown();
    }
 
    static class print implements runnable{
        @override
        public void run() {
            for (int i = 0; i < 10; i++) {
                try{
                    system.out.println("thread - "+thread.currentthread().getname()+" delay 5 second and sleep 2 second "+ new date());
                    thread.sleep(2000);
                }catch (exception e){
                    e.printstacktrace();
                }
            }
        }
    }
}

结果:

一篇文章带你了解Java中ThreadPool线程池

定时执行示例:调用scheduleatfixedrate方法,四个参数:task,initialdelay,period,timeunit

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class scheduledthreadpool {
    // corepoolsize = 1
    private static scheduledexecutorservice service = executors.newscheduledthreadpool(1);
 
    public static void main(string[] args) {
 
        system.out.println("thread - "+thread.currentthread().getname()+" begin "+ new date());
 
        service.scheduleatfixedrate(new print(),5,3,timeunit.seconds);
    }
 
    static class print implements runnable{
        @override
        public void run() {
            system.out.println("thread - "+thread.currentthread().getname()+" delay 5 second and period 3 second "+ new date());
        }
    }
}

结果:

一篇文章带你了解Java中ThreadPool线程池

(4) newcachedthreadpool

可缓存线程池,如果线程池长度超过处理需要,回收空闲线程,若无可回收,则新建线程。即若前一个任务已完成,则会接着复用该线程:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class cachedthreadpool {
 
    private static atomicinteger num = new atomicinteger(0);
 
    private static executorservice service = executors.newcachedthreadpool();
 
    public static void main(string[] args) {
        countsum c = new countsum();
        for (int i = 0; i < 3; i++) {
            try {
                service.submit(c);
                thread.sleep(1000);
            }catch (exception e){
                e.printstacktrace();
            }
        }
        service.shutdown();
    }
 
    static class countsum implements runnable{
        @override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                system.out.println("thread - "+thread.currentthread().getname()+" countsum= "+num.getandincrement());
            }
        }
    }
}

结果:thread.sleep(1000)即sleep一秒,上个任务完成可继续复用该线程,不需要创建新的线程

一篇文章带你了解Java中ThreadPool线程池

若将tread.sleep(1000)注释掉,你会发现有3个线程在跑

一篇文章带你了解Java中ThreadPool线程池

若感兴趣可以去了解一下它们的底层源码,对于cachedthreadpool而言,可新建线程最大数量为integer.maximum

2 线程池底层原理

以newfixedthreadpool为例

?
1
2
3
4
5
public static executorservice newfixedthreadpool(int nthreads) {
    return new threadpoolexecutor(nthreads, nthreads,
                                0l, timeunit.milliseconds,
                                new linkedblockingqueue<runnable>());
}
?
1
2
3
4
5
6
7
public threadpoolexecutor(int corepoolsize,
                          int maximumpoolsize,
                          long keepalivetime,
                          timeunit unit,
                          blockingqueue<runnable> workqueue) {
    this(corepoolsize, maximumpoolsize, keepalivetime, unit, workqueue,executors.defaultthreadfactory(), defaulthandler);
    }

线程池七大参数

  • corepoolsize:线程池中的常驻核心线程数
  • maximumpoolsize:线程池中能够容纳同时执行的最大线程数,必须大于1
  • keepalivetime:多余的空闲线程的存活时间;当前池中线程数量超过corepoolsize时,当空闲时间达到keepalivetime时,多余线程会被销毁
  • unit:keepalivetime的单位
  • workqueue:任务队列,被提交但尚未执行的任务
  • threadfactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认
  • handler:拒绝策略,表示当队列满了,并且工作线程大于等于线程池的最大线程数时如何来拒绝请求执行的runnable的策略

一篇文章带你了解Java中ThreadPool线程池

线程池四大流程

1)创建线程池后,开始等待请求

2)当调用execute()方法添加一个请求任务时,线程池会做以下判断:

  • 如果正在运行的线程数量小于corepoolsize,马上创建线程执行任务
  • 如果正在运行的线程数量大于等于corepoolsize,将该任务放入等待队列
  • 如果等待队列已满,但正在运行线程数量小于max,创建非核心线程执行任务
  • 如果队列满了且正在运行的线程数量大于max,线程池会启动饱和拒绝策略

3)当一个线程完成任务时,会从等待队列中取下一个任务来执行

4)当空闲线程超过keepalivetime定义时间,会判断:

  • 如果当前运行线程大于corepoolsize,该线程销毁
  • 所有线程执行完任务后,线程个数恢复到corepoolsize大小

 

3 线程池策略及分析

note:阿里巴巴java开发手册:线程池不允许使用executors去创建线程池,而是通过使用threadpoolexecutor的方式自定义线程池,规避资源耗尽的风险

executors返回的线程池对象的弊端:

1)fixedthreadpool和singlethreadpool:

​允许请求队列长度为integer.max_value,可能会堆积大量请求导致oom

2)cachedthreadpool和scheduledthreadpool:

​允许创建线程数量为integer.max_value,可能会创建大量的线程导致oom

 

拒绝策略

1)abortpolicy

​直接抛出rejectedexecutionexception异常阻止系统正常运行

2)callerrunspolicy

​"调用者运行"的调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量

3)discardpolicy

​该策略抛弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略

4)discardoldestpolicy

​抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务

 

如何设置maximumpoolsize大小

runtime.getruntime().availableprocessors()方法获取核数

cpu密集型

​maximumpoolsize设为核数+1

io密集型

​maximumpoolsize设为核数/阻塞系数

以上就是一篇文章-带你了解threadpool线程池的详细内容,更多关于threadpool线程池的资料请关注服务器之家其它相关文章!

原文链接:https://www.cnblogs.com/torima/p/15159336.html

延伸 · 阅读

精彩推荐
  • Java教程Java8中Stream使用的一个注意事项

    Java8中Stream使用的一个注意事项

    最近在工作中发现了对于集合操作转换的神器,java8新特性 stream,但在使用中遇到了一个非常重要的注意点,所以这篇文章主要给大家介绍了关于Java8中S...

    阿杜7482021-02-04
  • Java教程Java实现抢红包功能

    Java实现抢红包功能

    这篇文章主要为大家详细介绍了Java实现抢红包功能,采用多线程模拟多人同时抢红包,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    这篇文章主要介绍了Java使用SAX解析xml的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程升级IDEA后Lombok不能使用的解决方法

    升级IDEA后Lombok不能使用的解决方法

    最近看到提示IDEA提示升级,寻思已经有好久没有升过级了。升级完毕重启之后,突然发现好多错误,本文就来介绍一下如何解决,感兴趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java BufferWriter写文件写不进去或缺失数据的解决

    Java BufferWriter写文件写不进去或缺失数据的解决

    这篇文章主要介绍了Java BufferWriter写文件写不进去或缺失数据的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望...

    spcoder14552021-10-18
  • Java教程小米推送Java代码

    小米推送Java代码

    今天小编就为大家分享一篇关于小米推送Java代码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    富贵稳中求8032021-07-12
  • Java教程xml与Java对象的转换详解

    xml与Java对象的转换详解

    这篇文章主要介绍了xml与Java对象的转换详解的相关资料,需要的朋友可以参考下...

    Java教程网2942020-09-17
  • Java教程20个非常实用的Java程序代码片段

    20个非常实用的Java程序代码片段

    这篇文章主要为大家分享了20个非常实用的Java程序片段,对java开发项目有所帮助,感兴趣的小伙伴们可以参考一下 ...

    lijiao5352020-04-06