Java线程池学习笔记

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




    
    

    
    
        
        
        

        
        
        
        
        
        
        
        
        
        
    


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

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

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

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

总结:

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


测试:

Java配置:


        
        
        

        
        
        
        
        
        
        
        
        
        
    


代码:

ApplicationContext applicationContext =new ClassPathXmlApplicationContext("multiThread/spring-biz-threadpools.xml");
        ThreadPoolTaskExecutor asynThreadPool=(ThreadPoolTaskExecutor) applicationContext.getBean("asynThreadPool");
        List result =new ArrayList<>();
        List> list = new ArrayList<>();
        for (int i=0;i<10;++i){
            Future 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代码:

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

        for(Future 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 ,通过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类:

Java线程池学习笔记_第1张图片



参考资料:

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原理)





你可能感兴趣的:(Java学习)