我是靠谱客的博主 专一棒球,最近开发中收集的这篇文章主要介绍JAVA线程池----ThreadPoolExecutor机制,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

ThreadPoolExecutor机制 
一、概述 
1、ThreadPoolExecutor作为java.util.concurrent包对外提供基础实现,以内部线程池的形式对外提供管理任务执行,线程调度,线程池管理等等服务; 

 

2、Executors方法提供的线程服务,都是通过参数设置来实现不同的线程池机制。 

 

Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

3、当然用户还可以自定义线程池,了解其线程池管理的机制,有助于正确使用,避免错误使用导致严重故障。同时可以根据自己的需求实现自己的线程池 

二、核心构造方法讲解 
下面是ThreadPoolExecutor最核心的构造方法 

 

Java代码  收藏代码

  1. public ThreadPoolExecutor(int corePoolSize,  
  2.                               int maximumPoolSize,  
  3.                               long keepAliveTime,  
  4.                               TimeUnit unit,  
  5.                               BlockingQueue<Runnable> workQueue,  
  6.                               ThreadFactory threadFactory,  
  7.                               RejectedExecutionHandler handler) {  
  8.         if (corePoolSize < 0 ||  
  9.             maximumPoolSize <= 0 ||  
  10.             maximumPoolSize < corePoolSize ||  
  11.             keepAliveTime < 0)  
  12.             throw new IllegalArgumentException();  
  13.         if (workQueue == null || threadFactory == null || handler == null)  
  14.             throw new NullPointerException();  
  15.         this.corePoolSize = corePoolSize;  
  16.         this.maximumPoolSize = maximumPoolSize;  
  17.         this.workQueue = workQueue;  
  18.         this.keepAliveTime = unit.toNanos(keepAliveTime);  
  19.         this.threadFactory = threadFactory;  
  20.         this.handler = handler;  
  21.     }  


构造方法参数讲解

 

参数名作用
corePoolSize核心线程池大小
maximumPoolSize最大线程池大小
keepAliveTime线程池中超过corePoolSize数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true)使得核心线程有效时间
TimeUnitkeepAliveTime时间单位
workQueue阻塞任务队列
threadFactory新建线程工厂
RejectedExecutionHandler当提交任务数超过maxmumPoolSize+workQueue之和时,任务会交给RejectedExecutionHandler来处理

 


重点讲解: 
其中比较容易让人误解的是:corePoolSize,maximumPoolSize,workQueue之间关系。 

1.当线程池小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程。 
2.当线程池达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行 
3.当workQueue已满,且corePoolSize<maximumPoolSize时,新提交任务会创建新线程执行任务 
4.当提交任务数超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理 
5.当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程 
6.当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭 

 

线程池中任务有三种排队策略:

a. 直接提交。直接提交策略表示线程池不对任务进行缓存。新进任务直接提交给线程池,当线程池中没有空闲线程时,创建一个新的线程处理此任务。这种策略需要线程池具有无限增长的可能性。实现为:SynchronousQueue

b. 有界队列。当线程池中线程达到corePoolSize时,新进任务被放在队列里排队等待处理。有界队列(如ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。

c. 无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

  • AbortPolicy:默认策略,终止任务,抛出RejectedException
  • CallerRunsPolicy:在调用者线程执行当前任务,不抛异常
  • DiscardPolicy: 抛弃策略,直接丢弃任务,不抛异常
  • DiscardOldersPolicy:抛弃最老的任务,执行当前任务,不抛异常

线程管理机制图示: 

使用线程池的注意事项

r如何设置线程池参数:CPU密集型、IO密集型: CPU秘密型是2*CPU,另外一个是CPU/(1-阻塞系数)

  • 死锁

任何多线程程序都有死锁的风险,最简单的情形是两个线程AB,A持有锁1,请求锁2,B持有锁2,请求锁1。(这种情况在mysql的排他锁也会出现,不会数据库会直接报错提示)。线程池中还有另一种死锁:假设线程池中的所有工作线程都在执行各自任务时被阻塞,它们在等待某个任务A的执行结果。而任务A却处于队列中,由于没有空闲线程,一直无法得以执行。这样线程池的所有资源将一直阻塞下去,死锁也就产生了。

  • 系统资源不足

 如果线程池中的线程数目非常多,这些线程会消耗包括内存和其他系统资源在内的大量资源,从而严重影响系统性能。

  • 并发错误

线程池的工作队列依靠wait()和notify()方法来使工作线程及时取得任务,但这两个方法难以使用。如果代码错误,可能会丢失通知,导致工作线程一直保持空闲的状态,无视工作队列中需要处理的任务。因为最好使用一些比较成熟的线程池。

  • 线程泄漏

使用线程池的一个严重风险是线程泄漏。对于工作线程数目固定的线程池,如果工作线程在执行任务时抛出RuntimeException或Error,并且这些异常或错误没有被捕获,那么这个工作线程就异常终止,使线程池永久丢失了一个线程。(这一点太有意思)

另一种情况是,工作线程在执行一个任务时被阻塞,如果等待用户的输入数据,但是用户一直不输入数据,导致这个线程一直被阻塞。这样的工作线程名存实亡,它实际上不执行任何任务了。如果线程池中的所有线程都处于这样的状态,那么线程池就无法加入新的任务了。各种类型的线程池中一个严重的风险是线程泄漏,当从池中除去一个线程以执行一项任务,而在任务完成后该线程却没有返回池时,会发生这种情况。发生线程泄漏的一种情形出现在任务抛出一个 RuntimeException 或一个 Error 时。如果池类没有捕捉到它们,那么线程只会退出而线程池的大小将会永久减少一个。当这种情况发生的次数足够多时,线程池最终就为空,而且系统将停止,因为没有可用的线程来处理任务。 
有些任务可能会永远等待某些资源或来自用户的输入,而这些资源又不能保证变得可用,用户可能也已经回家了,诸如此类的任务会永久停止,而这些停止的任务也会引起和线程泄漏同样的问题。如果某个线程被这样一个任务永久地消耗着,那么它实际上就被从池除去了。对于这样的任务,应该要么只给予它们自己的线程,要么只让它们等待有限的时间。

  • 任务过载

当工作线程队列中有大量排队等待执行的任务时,这些任务本身可能会消耗太多的系统资源和引起资源缺乏。

 

综上所述,使用线程池时,要遵循以下原则:

  1. 如果任务A在执行过程中需要同步等待任务B的执行结果,那么任务A不适合加入到线程池的工作队列中。如果把像任务A一样的需要等待其他任务执行结果的加入到队列中,可能造成死锁
  2. 如果执行某个任务时可能会阻塞,并且是长时间的阻塞,则应该设定超时时间,避免工作线程永久的阻塞下去而导致线程泄漏。在服务器才程序中,当线程等待客户连接,或者等待客户发送的数据时,都可能造成阻塞,可以通过以下方式设置时间:

    调用ServerSocket的setSotimeout方法,设定等待客户连接的超时时间。

    对于每个与客户连接的socket,调用该socket的setSoTImeout方法,设定等待客户发送数据的超时时间。

  3. 了解任务的特点,分析任务是执行经常会阻塞io操作,还是执行一直不会阻塞的运算操作。前者时断时续的占用cpu,而后者具有更高的利用率。预计完成任务大概需要多长时间,是短时间任务还是长时间任务,然后根据任务的特点,对任务进行分类,然后把不同类型的任务加入到不同的线程池的工作队列中,这样就可以根据任务的特点,分配调整每个线程池
  4. 调整线程池的大小。线程池的最佳大小主要取决于系统的可用cpu的数目,以及工作队列中任务的特点。假如一个具有N个cpu的系统上只有一个工作队列,并且其中全部是运算性质(不会阻塞)的任务,那么当线程池拥有N或N+1个工作线程时,一般会获得最大的cpu使用率。

    如果工作队列中包含会执行IO操作并经常阻塞的任务,则要让线程池的大小超过可用 cpu的数量,因为并不是所有的工作线程都一直在工作。选择一个典型的任务,然后估计在执行这个任务的工程中,等待时间与实际占用cpu进行运算的时间的比例WT/ST。对于一个具有N个cpu的系统,需要设置大约N*(1+WT/ST)个线程来保证cpu得到充分利用。

    当然,cpu利用率不是调整线程池过程中唯一要考虑的事项,随着线程池工作数目的增长,还会碰到内存或者其他资源的限制,如套接字,打开的文件句柄或数据库连接数目等。要保证多线程消耗的系统资源在系统承受的范围之内。

  5. 避免任务过载。服务器应根据系统的承载能力,限制客户并发连接的数目。当客户的连接超过了限制值,服务器可以拒绝连接,并进行友好提示,或者限制队列长度.

三、Executors提供的线程池配置方案 

1、构造一个固定线程数目的线程池,配置的corePoolSize与maximumPoolSize大小相同,同时使用了一个无界LinkedBlockingQueue存放阻塞任务,因此多余的任务将存在再阻塞队列,不会由RejectedExecutionHandler处理 

 

 

Java代码  收藏代码

  1. public static ExecutorService newFixedThreadPool(int nThreads) {  
  2.         return new ThreadPoolExecutor(nThreads, nThreads,  
  3.                                       0L, TimeUnit.MILLISECONDS,  
  4.                                       new LinkedBlockingQueue<Runnable>());  
  5.     }  


2、构造一个缓冲功能的线程池,配置corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE,keepAliveTime=60s,以及一个无容量的阻塞队列 SynchronousQueue,因此任务提交之后,将会创建新的线程执行;线程空闲超过60s将会销毁

 

Java代码  收藏代码

  1. public static ExecutorService newCachedThreadPool() {  
  2.         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,  
  3.                                       60L, TimeUnit.SECONDS,  
  4.                                       new SynchronousQueue<Runnable>());  
  5.     }  


3、构造一个只支持一个线程的线程池,配置corePoolSize=maximumPoolSize=1,无界阻塞队列LinkedBlockingQueue;保证任务由一个线程串行执行

 

Java代码  收藏代码

  1. public static ExecutorService newSingleThreadExecutor() {  
  2.         return new FinalizableDelegatedExecutorService  
  3.             (new ThreadPoolExecutor(11,  
  4.                                     0L, TimeUnit.MILLISECONDS,  
  5.                                     new LinkedBlockingQueue<Runnable>()));  
  6.     }  


4、构造有定时功能的线程池,配置corePoolSize,无界延迟阻塞队列DelayedWorkQueue;有意思的是:maximumPoolSize=Integer.MAX_VALUE,由于DelayedWorkQueue是无界队列,所以这个值是没有意义的

 

Java代码  收藏代码

  1. public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {  
  2.         return new ScheduledThreadPoolExecutor(corePoolSize);  
  3.     }  
  4.   
  5. public static ScheduledExecutorService newScheduledThreadPool(  
  6.             int corePoolSize, ThreadFactory threadFactory) {  
  7.         return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);  
  8.     }  
  9.   
  10. public ScheduledThreadPoolExecutor(int corePoolSize,  
  11.                              ThreadFactory threadFactory) {  
  12.         super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,  
  13.               new DelayedWorkQueue(), threadFactory);  
  14.     }  



四、定制属于自己的非阻塞线程池

 

Java代码  收藏代码

  1. import java.util.concurrent.ArrayBlockingQueue;  
  2. import java.util.concurrent.ExecutorService;  
  3. import java.util.concurrent.RejectedExecutionHandler;  
  4. import java.util.concurrent.ThreadFactory;  
  5. import java.util.concurrent.ThreadPoolExecutor;  
  6. import java.util.concurrent.TimeUnit;  
  7. import java.util.concurrent.atomic.AtomicInteger;  
  8.   
  9.   
  10. public class CustomThreadPoolExecutor {  
  11.   
  12.       
  13.     private ThreadPoolExecutor pool = null;  
  14.       
  15.       
  16.     /** 
  17.      * 线程池初始化方法 
  18.      *  
  19.      * corePoolSize 核心线程池大小----10 
  20.      * maximumPoolSize 最大线程池大小----30 
  21.      * keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit 
  22.      * TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES 
  23.      * workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(10)====10容量的阻塞队列 
  24.      * threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂 
  25.      * rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时, 
  26.      *                          即当提交第41个任务时(前面线程都没有执行完,此测试方法中用sleep(100)), 
  27.      *                                任务会交给RejectedExecutionHandler来处理 
  28.      */  
  29.     public void init() {  
  30.         pool = new ThreadPoolExecutor(  
  31.                 10,  
  32.                 30,  
  33.                 30,  
  34.                 TimeUnit.MINUTES,  
  35.                 new ArrayBlockingQueue<Runnable>(10),  
  36.                 new CustomThreadFactory(),  
  37.                 new CustomRejectedExecutionHandler());  
  38.     }  
  39.   
  40.       
  41.     public void destory() {  
  42.         if(pool != null) {  
  43.             pool.shutdownNow();  
  44.         }  
  45.     }  
  46.       
  47.       
  48.     public ExecutorService getCustomThreadPoolExecutor() {  
  49.         return this.pool;  
  50.     }  
  51.       
  52.     private class CustomThreadFactory implements ThreadFactory {  
  53.   
  54.         private AtomicInteger count = new AtomicInteger(0);  
  55.           
  56.         @Override  
  57.         public Thread newThread(Runnable r) {  
  58.             Thread t = new Thread(r);  
  59.             String threadName = CustomThreadPoolExecutor.class.getSimpleName() + count.addAndGet(1);  
  60.             System.out.println(threadName);  
  61.             t.setName(threadName);  
  62.             return t;  
  63.         }  
  64.     }  
  65.       
  66.       
  67.     private class CustomRejectedExecutionHandler implements RejectedExecutionHandler {  
  68.   
  69.         @Override  
  70.         public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {  
  71.             // 记录异常  
  72.             // 报警处理等  
  73.             System.out.println("error.............");  
  74.         }  
  75.     }  
  76.       
  77.       
  78.       
  79.     // 测试构造的线程池  
  80.     public static void main(String[] args) {  
  81.         CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor();  
  82.         // 1.初始化  
  83.         exec.init();  
  84.           
  85.         ExecutorService pool = exec.getCustomThreadPoolExecutor();  
  86.         for(int i=1; i<100; i++) {  
  87.             System.out.println("提交第" + i + "个任务!");  
  88.             pool.execute(new Runnable() {  
  89.                 @Override  
  90.                 public void run() {  
  91.                     try {  
  92.                         Thread.sleep(3000);  
  93.                     } catch (InterruptedException e) {  
  94.                         e.printStackTrace();  
  95.                     }  
  96.                     System.out.println("running=====");  
  97.                 }  
  98.             });  
  99.         }  
  100.           
  101.           
  102.           
  103.         // 2.销毁----此处不能销毁,因为任务没有提交执行完,如果销毁线程池,任务也就无法执行了  
  104.         // exec.destory();  
  105.           
  106.         try {  
  107.             Thread.sleep(10000);  
  108.         } catch (InterruptedException e) {  
  109.             e.printStackTrace();  
  110.         }  
  111.     }  
  112. }  


方法中建立一个核心线程数为30个,缓冲队列有10个的线程池。每个线程任务,执行时会先睡眠3秒,保证提交10任务时,线程数目被占用完,再提交30任务时,阻塞队列被占用完,,这样提交第41个任务是,会交给CustomRejectedExecutionHandler 异常处理类来处理。 

提交任务的代码如下:

 

Java代码  收藏代码

  1. public void execute(Runnable command) {  
  2.         if (command == null)  
  3.             throw new NullPointerException();  
  4.         /* 
  5.          * Proceed in 3 steps: 
  6.          * 
  7.          * 1. If fewer than corePoolSize threads are running, try to 
  8.          * start a new thread with the given command as its first 
  9.          * task.  The call to addWorker atomically checks runState and 
  10.          * workerCount, and so prevents false alarms that would add 
  11.          * threads when it shouldn't, by returning false. 
  12.          * 
  13.          * 2. If a task can be successfully queued, then we still need 
  14.          * to double-check whether we should have added a thread 
  15.          * (because existing ones died since last checking) or that 
  16.          * the pool shut down since entry into this method. So we 
  17.          * recheck state and if necessary roll back the enqueuing if 
  18.          * stopped, or start a new thread if there are none. 
  19.          * 
  20.          * 3. If we cannot queue task, then we try to add a new 
  21.          * thread.  If it fails, we know we are shut down or saturated 
  22.          * and so reject the task. 
  23.          */  
  24.         int c = ctl.get();  
  25.         if (workerCountOf(c) < corePoolSize) {  
  26.             if (addWorker(command, true))  
  27.                 return;  
  28.             c = ctl.get();  
  29.         }  
  30.         if (isRunning(c) && workQueue.offer(command)) {  
  31.             int recheck = ctl.get();  
  32.             if (! isRunning(recheck) && remove(command))  
  33.                 reject(command);  
  34.             else if (workerCountOf(recheck) == 0)  
  35.                 addWorker(nullfalse);  
  36.         }  
  37.         else if (!addWorker(command, false))  
  38.             reject(command);  
  39.     }  


注意:41以后提交的任务就不能正常处理了,因为,execute中提交到任务队列是用的offer方法,如上面代码,这个方法是非阻塞的,所以就会交给CustomRejectedExecutionHandler 来处理,所以对于大数据量的任务来说,这种线程池,如果不设置队列长度会OOM,设置队列长度,会有任务得不到处理,接下来我们构建一个阻塞的自定义线程池 

五、定制属于自己的阻塞线程池

 

Java代码  收藏代码

  1. package com.tongbanjie.trade.test.commons;  
  2.   
  3. import java.util.concurrent.ArrayBlockingQueue;  
  4. import java.util.concurrent.ExecutorService;  
  5. import java.util.concurrent.RejectedExecutionHandler;  
  6. import java.util.concurrent.ThreadFactory;  
  7. import java.util.concurrent.ThreadPoolExecutor;  
  8. import java.util.concurrent.TimeUnit;  
  9. import java.util.concurrent.atomic.AtomicInteger;  
  10.   
  11. public class CustomThreadPoolExecutor {    
  12.         
  13.         
  14.     private ThreadPoolExecutor pool = null;    
  15.         
  16.         
  17.     /**  
  18.      * 线程池初始化方法  
  19.      *   
  20.      * corePoolSize 核心线程池大小----1  
  21.      * maximumPoolSize 最大线程池大小----3  
  22.      * keepAliveTime 线程池中超过corePoolSize数目的空闲线程最大存活时间----30+单位TimeUnit  
  23.      * TimeUnit keepAliveTime时间单位----TimeUnit.MINUTES  
  24.      * workQueue 阻塞队列----new ArrayBlockingQueue<Runnable>(5)====5容量的阻塞队列  
  25.      * threadFactory 新建线程工厂----new CustomThreadFactory()====定制的线程工厂  
  26.      * rejectedExecutionHandler 当提交任务数超过maxmumPoolSize+workQueue之和时,  
  27.      *                          即当提交第41个任务时(前面线程都没有执行完,此测试方法中用sleep(100)),  
  28.      *                                任务会交给RejectedExecutionHandler来处理  
  29.      */    
  30.     public void init() {    
  31.         pool = new ThreadPoolExecutor(    
  32.                 1,    
  33.                 3,    
  34.                 30,    
  35.                 TimeUnit.MINUTES,    
  36.                 new ArrayBlockingQueue<Runnable>(5),    
  37.                 new CustomThreadFactory(),    
  38.                 new CustomRejectedExecutionHandler());    
  39.     }    
  40.     
  41.         
  42.     public void destory() {    
  43.         if(pool != null) {    
  44.             pool.shutdownNow();    
  45.         }    
  46.     }    
  47.         
  48.         
  49.     public ExecutorService getCustomThreadPoolExecutor() {    
  50.         return this.pool;    
  51.     }    
  52.         
  53.     private class CustomThreadFactory implements ThreadFactory {    
  54.     
  55.         private AtomicInteger count = new AtomicInteger(0);    
  56.             
  57.         @Override    
  58.         public Thread newThread(Runnable r) {    
  59.             Thread t = new Thread(r);    
  60.             String threadName = CustomThreadPoolExecutor.class.getSimpleName() + count.addAndGet(1);    
  61.             System.out.println(threadName);    
  62.             t.setName(threadName);    
  63.             return t;    
  64.         }    
  65.     }    
  66.         
  67.         
  68.     private class CustomRejectedExecutionHandler implements RejectedExecutionHandler {    
  69.     
  70.         @Override    
  71.         public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {    
  72.             try {  
  73.                                 // 核心改造点,由blockingqueue的offer改成put阻塞方法  
  74.                 executor.getQueue().put(r);  
  75.             } catch (InterruptedException e) {  
  76.                 e.printStackTrace();  
  77.             }  
  78.         }    
  79.     }    
  80.         
  81.         
  82.         
  83.     // 测试构造的线程池    
  84.     public static void main(String[] args) {    
  85.           
  86.         CustomThreadPoolExecutor exec = new CustomThreadPoolExecutor();    
  87.         // 1.初始化    
  88.         exec.init();    
  89.             
  90.         ExecutorService pool = exec.getCustomThreadPoolExecutor();    
  91.         for(int i=1; i<100; i++) {    
  92.             System.out.println("提交第" + i + "个任务!");    
  93.             pool.execute(new Runnable() {    
  94.                 @Override    
  95.                 public void run() {    
  96.                     try {    
  97.                         System.out.println(">>>task is running=====");   
  98.                         TimeUnit.SECONDS.sleep(10);  
  99.                     } catch (InterruptedException e) {    
  100.                         e.printStackTrace();    
  101.                     }    
  102.                 }    
  103.             });    
  104.         }    
  105.             
  106.             
  107.         // 2.销毁----此处不能销毁,因为任务没有提交执行完,如果销毁线程池,任务也就无法执行了    
  108.         // exec.destory();    
  109.             
  110.         try {    
  111.             Thread.sleep(10000);    
  112.         } catch (InterruptedException e) {    
  113.             e.printStackTrace();    
  114.         }    
  115.     }    
  116. }    



解释:当提交任务被拒绝时,进入拒绝机制,我们实现拒绝方法,把任务重新用阻塞提交方法put提交,实现阻塞提交任务功能,防止队列过大,OOM,提交被拒绝方法在下面 

   

Java代码  收藏代码

  1. public void execute(Runnable command) {  
  2.         if (command == null)  
  3.             throw new NullPointerException();  
  4.   
  5.         int c = ctl.get();  
  6.         if (workerCountOf(c) < corePoolSize) {  
  7.             if (addWorker(command, true))  
  8.                 return;  
  9.             c = ctl.get();  
  10.         }  
  11.         if (isRunning(c) && workQueue.offer(command)) {  
  12.             int recheck = ctl.get();  
  13.             if (! isRunning(recheck) && remove(command))  
  14.                 reject(command);  
  15.             else if (workerCountOf(recheck) == 0)  
  16.                 addWorker(nullfalse);  
  17.         }  
  18.         else if (!addWorker(command, false))  
  19.             // 进入拒绝机制, 我们把runnable任务拿出来,重新用阻塞操作put,来实现提交阻塞功能  
  20.             reject(command);  
  21.     }  

 

 


总结: 
1、用ThreadPoolExecutor自定义线程池,看线程是的用途,如果任务量不大,可以用无界队列,如果任务量非常大,要用有界队列,防止OOM 
2、如果任务量很大,还要求每个任务都处理成功,要对提交的任务进行阻塞提交,重写拒绝机制,改为阻塞提交。保证不抛弃一个任务 
3、最大线程数一般设为2N+1最好,N是CPU核数 
4、核心线程数,看应用,如果是任务,一天跑一次,设置为0,合适,因为跑完就停掉了,如果是常用线程池,看任务量,是保留一个核心还是几个核心线程数 
5、如果要获取任务执行结果,用CompletionService,但是注意,获取任务的结果的要重新开一个线程获取,如果在主线程获取,就要等任务都提交后才获取,就会阻塞大量任务结果,队列过大OOM,所以最好异步开个线程获取结果

 

 

最后

以上就是专一棒球为你收集整理的JAVA线程池----ThreadPoolExecutor机制的全部内容,希望文章能够帮你解决JAVA线程池----ThreadPoolExecutor机制所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部