Java线程池学习笔记

Spring的ThreadPoolTaskExecutor:
ThreadPoolTaskExecutor是借助JDK并发包中的ThreadPoolExecutor,类ThreadPoolTaskExecutor中包含ThreadPoolExecutor。

</pre><pre code_snippet_id="1576841" snippet_file_name="blog_20160211_1_1277057" name="code" class="java"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"
       default-lazy-init="false">

    <!-- callerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 -->
    <bean id="callerRunsPolicy" class="java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy"/>

    <!-- 线程池配置 -->
    <bean id="asynThreadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 线程组&名称 -->
        <property name="threadGroupName" value="epp-tg1"/>
        <property name="threadNamePrefix" value="remote-query-task"/>

        <!-- 线程池维护线程的最少数量 -->
        <property name="corePoolSize" value="1"/>
        <!-- 线程池维护线程所允许的空闲时间,5分钟 -->
        <property name="keepAliveSeconds" value="300"/>
        <!-- 线程池维护线程的最大数量 -->
        <property name="maxPoolSize" value="200"/>
        <!-- 线程池所使用的缓冲队列 -->
        <property name="queueCapacity" value="100"/>
        <!-- CallerRunsPolicy -->
        <property name="rejectedExecutionHandler" ref="callerRunsPolicy"/>
    </bean>

</beans>


(1)    线程池数量小于corePoolSize,则增加线程。即使线程池中的线程都处于空闲状态,也要创建新的线程来处理。

(2)    如果线程数量等于corePoolSize,则把请求放在workQueue中,池子里的线程空闲线程就去从workQueue中取任务并处理。

(3)    如果workQueue已满,则新建线程加入线程池,并处理请求,如果池子的大小撑到了maxPoolsize,就用rejectedExecutionHangdler 指定的策略来处理此任务。

(4)    如果当线程数大于corePoolsize的时候,多余的线程会等待keepAliveTime长时间,如果无请求可处理就自行销毁。(线程数小于corePoolSize时,线程不会自动销毁,除非手动调用对应的方法)

总结:

处理任务的优先级为:核心线程corePoolSize、任务队列workQueue,最大线程maxPoolSize,如果三者都满了,使用handle处理被拒绝的任务。


测试:

Java配置:

<bean id="asynThreadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 线程组&名称 -->
        <property name="threadGroupName" value="epp-tg1"/>
        <property name="threadNamePrefix" value="remote-query-task"/>

        <!-- 线程池维护线程的最少数量 -->
        <property name="corePoolSize" value="1"/>
        <!-- 线程池维护线程所允许的空闲时间,5分钟 -->
        <property name="keepAliveSeconds" value="1"/>
        <!-- 线程池维护线程的最大数量 -->
        <property name="maxPoolSize" value="100"/>
        <!-- 线程池所使用的缓冲队列 -->
        <property name="queueCapacity" value="3"/>
        <!-- CallerRunsPolicy -->
        <property name="rejectedExecutionHandler" ref="callerRunsPolicy"/>
    </bean>


代码:

ApplicationContext applicationContext =new ClassPathXmlApplicationContext("multiThread/spring-biz-threadpools.xml");
        ThreadPoolTaskExecutor asynThreadPool=(ThreadPoolTaskExecutor) applicationContext.getBean("asynThreadPool");
        List<String> result =new ArrayList<>();
        List<Future<String>> list = new ArrayList<>();
        for (int i=0;i<10;++i){
            Future<String> future = asynThreadPool.submit(()->methodTest());
            System.out.println("活跃线程数:"+Thread.activeCount());
            list.add(future);
        }


运行结果:

活跃线程数:3
活跃线程数:3
活跃线程数:3
活跃线程数:3
活跃线程数:4
活跃线程数:5
活跃线程数:6

备注:活跃线程数包含主线程。

任务1,新建线程,当前活跃线程数为2;

任务2,corePoolSize已满,所以会将任务放在workQueue中,当前活跃线程数为2,

任务3,corePoolSize已满,所以会将任务放在workQueue中,当前活跃线程数为2,

任务4:corePoolSize已满,所以会将任务放在workQueue中,当前活跃线程数为2,

任务5:corePoolSize已满,workQueue已满,还未达到maxPoolSize,所以会新建线程,

.......




java代码:

<pre name="code" class="java"> @Test
    public void  test() throws ExecutionException, InterruptedException {
        ApplicationContext applicationContext =new ClassPathXmlApplicationContext("multiThread/spring-biz-threadpools.xml");
        ThreadPoolTaskExecutor asynThreadPool=(ThreadPoolTaskExecutor) applicationContext.getBean("asynThreadPool");
        List<String> result =new ArrayList<>();
        List<Future<String>> list = new ArrayList<>();
        for (int i=0;i<10;++i){
            Future<String> future = asynThreadPool.submit(()->methodTest());
            System.out.println("活跃线程数:"+Thread.activeCount());
            list.add(future);
        }

        for(Future<String> future:list){
            try{
                System.out.println(future.get());
            }catch (Exception e){
                e.printStackTrace();
            }
        }


        Thread.sleep(100000);


        System.out.println("test");

    }

    public String methodTest() throws Exception {
       System.out.println("thread test "+i );
       Thread.sleep(10000);
        return "call()方法被自动调用,线程名称:"  + Thread.currentThread().getName();
    }



 


注意:

如果线程抛出异常,在调用future.get()方法时,会将异常抛出到外部,抛出的异常为ExecutionException。在调用future.get()方法时,会等待线程运行完成,并取得返回结果。

通过e.getCause取出导致抛出异常的原因。


submit和execute的区别:

(1) 接受的参数不一样

submit接受的参数:接受runable或者Callable对象

execute接收的参数:接收runnable对象

(2) submit有返回值,execute无返回值

submit的返回值未Future<T> ,通过future类的get方法获取到返回值

(3) submit处理exception的方式和execute不同

submit处理异常:如果某个线程抛出异常,则通过future.get()获取到该异常

execute() 无法返回异常,run方法不能抛出异常,所以方法内部必须捕获异常。


runnable和callable的差别:

(1) Callable规定的方法是call(), Runnable规定的方法是run

(2) Callable的任务执行后可返回值,而runnable的认识是不能返回值的

(3) call方法可以抛出异常,run方法不可以

(4)运行Callable任务可以拿到一个Future对象,Future表示异步计算的结果,可通过get()方法取出返回值,如果线程出现异常,Future.get()会抛出InterruptedException或者ExecutionException,如果线程已取消,会抛出CancellationException。


线程容量已经达到饱和时,对于再到达的线程的处理策略:

当 Executor 已经关闭,并且 Executor 将有限边界用于最大线程和工作队列容量,且已经饱和时,在方法 execute(java.lang.Runnable) 中提交的新任务将被拒绝。在以上两种情况下,execute 方法都将调用其RejectedExecutionHandler 的RejectedExecutionHandler.rejectedExecution(java.lang.Runnable, java.util.concurrent.ThreadPoolExecutor) 方法。下面提供了四种预定义的处理程序策略:
(1)在默认的 ThreadPoolExecutor.AbortPolicy 中,处理程序遭到拒绝将抛出运行时RejectedExecutionException。
(2) 在 ThreadPoolExecutor.CallerRunsPolicy 中,线程调用运行该任务的execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
(3) 在 ThreadPoolExecutor.DiscardPolicy 中,不能执行的任务将被删除。
(4) 在 ThreadPoolExecutor.DiscardOldestPolicy 中,如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)。
定义和使用其他种类的 RejectedExecutionHandler 类也是可能的,但这样做需要非常小心,尤其是当策略仅用于特定容量或排队策略时。


ThreadPoolExecutor类:




参考资料:

http://www.importnew.com/17633.html (对应的英文文章:https://blog.bramp.net/post/2015/12/17/the-importance-of-tuning-your-thread-pools/)

http://www.importnew.com/17820.html(主要讲讲解了java的ThreadPoolExecutor原理)





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java是一种广泛使用的编程语言,有简单、面向对象、跨平台等特点。下面是Java学习的一些重要知识点和学习笔记: 1. Java基础: - 数据类型:Java提供了多种数据类型,包括基本数据类型和引用数据类型。 - 控制流程:学习如何使用条件语句(if-else、switch)、循环语句(for、while)等控制程序的流程。 - 数组:了解如何声明、初始化和操作数组。 - 方法:学习如何定义和调用方法,以及方法的参数和返回值。 - 类和对象:理解类和对象的概念,学习如何定义类、创建对象和使用类的成员变量和方法。 - 继承和多态:掌握继承和多态的概念,了解如何使用继承创建子类,并实现方法的重写和多态的应用。 2. 面向对象编程: - 封装:学习如何使用访问修饰符(public、private、protected)来控制类的成员的访问权限。 - 继承:了解继承的概念和作用,学习如何使用extends关键字创建子类。 - 多态:理解多态的概念和实现方式,学习如何使用父类引用指向子类对象,实现方法的动态绑定。 3. 异常处理: - 异常的分类:了解异常的分类(Checked Exception和Unchecked Exception)和常见的异常类型。 - 异常处理机制:学习如何使用try-catch语句捕获和处理异常,以及使用throws关键字声明方法可能抛出的异常。 4. 输入输出: - 文件操作:学习如何读写文件,包括使用File类、字节流和字符流等。 - 序列化:了解对象的序列化和反序列化,学习如何将对象保存到文件或网络中。 5. 集合框架: - 学习Java提供的集合框架,包括List、Set、Map等常用的集合类,以及它们的特点和用法。 6. 多线程编程: - 学习如何创建和管理线程,了解线程同步和线程间通信的方法。 7. 数据库连接: - 学习如何使用Java连接数据库,执行SQL语句,进行数据的增删改查操作。 以上是Java学习的一些重要知识点和学习笔记,希望对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值