频道栏目
首页 > 程序开发 > 软件开发 > Java > 正文
JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue
2017-11-06 20:58:08         来源:ycr19921121的博客  
收藏   我要投稿

JAVA线程池ThreadPoolExecutor与阻塞队列BlockingQueue,从Java5开始,Java提供了自己的线程池。每次只执行指定数量的线程,java.util.concurrent.ThreadPoolExecutor 就是这样的线程池。以下是我的学习过程。

首先是构造函数签名如下:

publicThreadPoolExecutor(intcorePoolSize,intmaximumPoolSize,longkeepAliveTime,TimeUnitunit,BlockingQueueworkQueue,RejectedExecutionHandlerhandler); 参数介绍:

corePoolSize核心线程数,指保留的线程池大小(不超过maximumPoolSize值时,线程池中最多有corePoolSize 个线程工作)。

maximumPoolSize指的是线程池的最大大小(线程池中最大有corePoolSize 个线程可运行)。

keepAliveTime指的是空闲线程结束的超时时间(当一个线程不工作时,过keepAliveTime 长时间将停止该线程)。

unit是一个枚举,表示 keepAliveTime 的单位(有NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS,7个可选值)。

workQueue表示存放任务的队列(存放需要被线程池执行的线程队列)。

handler拒绝策略(添加任务失败后如何处理该任务).

1、线程池刚创建时,里面没有一个线程。任务队列是作为参数传进来的。不过,就算队列里面有任务,线程池也不会马上执行它们。

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

a. 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;

b. 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列。

c. 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建线程运行这个任务;

d. 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会抛出异常,告诉调用者“我不能再接受任务了”。

3、当一个线程完成任务时,它会从队列中取下一个任务来执行。

4、当一个线程无事可做,超过一定的时间(keepAliveTime)时,线程池会判断,如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。

这个过程说明,并不是先加入任务就一定会先执行。假设队列大小为 4,corePoolSize为2,maximumPoolSize为6,那么当加入15个任务时,执行的顺序类似这样:首先执行任务 1、2,然后任务3~6被放入队列。这时候队列满了,任务7、8、9、10 会被马上执行,而任务 11~15 则会抛出异常。最终顺序是:1、2、7、8、9、10、3、4、5、6。当然这个过程是针对指定大小的ArrayBlockingQueue来说,如果是LinkedBlockingQueue,因为该队列无大小限制,所以不存在上述问题。

示例一,LinkedBlockingQueue队列使用:

importjava.util.concurrent.BlockingQueue;

importjava.util.concurrent.LinkedBlockingQueue;

importjava.util.concurrent.ThreadPoolExecutor;

importjava.util.concurrent.TimeUnit;

/**

*Createdon2011-12-28

*

Description:[Java线程池学习]

*@authorshixing_11@sina.com

*/

publicclassThreadPoolTestimplementsRunnable{

publicvoidrun(){

synchronized(this){

try{

System.out.println(Thread.currentThread().getName());

Thread.sleep(3000);

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

}

publicstaticvoidmain(String[]args){

BlockingQueuequeue=newLinkedBlockingQueue();

ThreadPoolExecutorexecutor=newThreadPoolExecutor(2,6,1,TimeUnit.DAYS,queue);

for(inti=0;i<10;i++){

executor.execute(newThread(newThreadPoolTest(),"TestThread".concat(""+i)));

intthreadSize=queue.size();

System.out.println("线程队列大小为-->"+threadSize);

}

executor.shutdown();

}

}

importjava.util.concurrent.BlockingQueue;

importjava.util.concurrent.LinkedBlockingQueue;

importjava.util.concurrent.ThreadPoolExecutor;

importjava.util.concurrent.TimeUnit;

/**

*Createdon2011-12-28

*

Description:[Java线程池学习]

*@authorshixing_11@sina.com

*/

publicclassThreadPoolTestimplementsRunnable{

publicvoidrun(){

synchronized(this){

try{

System.out.println(Thread.currentThread().getName());

Thread.sleep(3000);

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

}

publicstaticvoidmain(String[]args){

BlockingQueuequeue=newLinkedBlockingQueue();

ThreadPoolExecutorexecutor=newThreadPoolExecutor(2,6,1,TimeUnit.DAYS,queue);

for(inti=0;i<10;i++){

executor.execute(newThread(newThreadPoolTest(),"TestThread".concat(""+i)));

intthreadSize=queue.size();

System.out.println("线程队列大小为-->"+threadSize);

}

executor.shutdown();

}

} 输出结果如下:

线程队列大小为-->0

线程名称:pool-1-thread-1

线程队列大小为-->0

线程队列大小为-->1

线程队列大小为-->2

线程队列大小为-->3

线程队列大小为-->4

线程队列大小为-->5

线程队列大小为-->6

线程队列大小为-->7

线程队列大小为-->8

线程名称:pool-1-thread-2

线程名称:pool-1-thread-1

线程名称:pool-1-thread-2

线程名称:pool-1-thread-1

线程名称:pool-1-thread-2

线程名称:pool-1-thread-1

线程名称:pool-1-thread-2

线程名称:pool-1-thread-1

线程名称:pool-1-thread-2

可见,线程队列最大为8,共执行了10个线线程。因为是从线程池里运行的线程,所以虽然将线程的名称设为"TestThread".concat(""+i),但输出后还是变成了pool-1-thread-x。

示例二,LinkedBlockingQueue队列使用:

importjava.util.concurrent.BlockingQueue;

importjava.util.concurrent.ArrayBlockingQueue;

importjava.util.concurrent.ThreadPoolExecutor;

importjava.util.concurrent.TimeUnit;

/**

*Createdon2011-12-28

*

Description:[Java线程池学习]

*@authorshixing_11@sina.com

*/

publicclassThreadPoolTestimplementsRunnable{

publicvoidrun(){

synchronized(this){

try{

System.out.println("线程名称:"+Thread.currentThread().getName());

Thread.sleep(3000);//休眠是为了让该线程不至于执行完毕后从线程池里释放

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

}

publicstaticvoidmain(String[]args)throwsInterruptedException{

BlockingQueuequeue=newArrayBlockingQueue(4);//固定为4的线程队列

ThreadPoolExecutorexecutor=newThreadPoolExecutor(2,6,1,TimeUnit.DAYS,queue);

for(inti=0;i<10;i++){

executor.execute(newThread(newThreadPoolTest(),"TestThread".concat(""+i)));

intthreadSize=queue.size();

System.out.println("线程队列大小为-->"+threadSize);

}

executor.shutdown();

}

}

importjava.util.concurrent.BlockingQueue;

importjava.util.concurrent.ArrayBlockingQueue;

importjava.util.concurrent.ThreadPoolExecutor;

importjava.util.concurrent.TimeUnit;

/**

*Createdon2011-12-28

*

Description:[Java线程池学习]

*@authorshixing_11@sina.com

*/

publicclassThreadPoolTestimplementsRunnable{

publicvoidrun(){

synchronized(this){

try{

System.out.println("线程名称:"+Thread.currentThread().getName());

Thread.sleep(3000);//休眠是为了让该线程不至于执行完毕后从线程池里释放

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

}

publicstaticvoidmain(String[]args)throwsInterruptedException{

BlockingQueuequeue=newArrayBlockingQueue(4);//固定为4的线程队列

ThreadPoolExecutorexecutor=newThreadPoolExecutor(2,6,1,TimeUnit.DAYS,queue);

for(inti=0;i<10;i++){

executor.execute(newThread(newThreadPoolTest(),"TestThread".concat(""+i)));

intthreadSize=queue.size();

System.out.println("线程队列大小为-->"+threadSize);

}

executor.shutdown();

}

} 输出结果如下:

线程队列大小为-->0

线程队列大小为-->0

线程队列大小为-->1

线程队列大小为-->2

线程队列大小为-->3

线程队列大小为-->4

线程队列大小为-->4

线程队列大小为-->4

线程队列大小为-->4

线程名称:pool-1-thread-1

线程名称:pool-1-thread-3

线程名称:pool-1-thread-2

线程名称:pool-1-thread-4

线程队列大小为-->4

线程名称:pool-1-thread-5

线程名称:pool-1-thread-6

线程名称:pool-1-thread-5

线程名称:pool-1-thread-6

线程名称:pool-1-thread-4

线程名称:pool-1-thread-2

可见,总共10个线程,因为核心线程数为2,2个线程被立即运行,线程队列大小为4,所以4个线程被加入队列,最大线程数为6,还能运行6-2=4个,其10个线程的其余4个线程又立即运行了。

如果将我们要运行的线程数10改为11,则由于最大线程数6+线程队列大小4=10<11,则根据线程池工作原则,最后一个线程将被拒绝策略拒绝,将示例二的main方法改为如下:

publicstaticvoidmain(String[]args)throwsInterruptedException{

ArrayBlockingQueuequeue=newArrayBlockingQueue(4);//固定为4的线程队列

ThreadPoolExecutorexecutor=newThreadPoolExecutor(2,6,1,TimeUnit.DAYS,queue);

for(inti=0;i<11;i++){

executor.execute(newThread(newThreadPoolTest(),"TestThread".concat(""+i)));

intthreadSize=queue.size();

System.out.println("线程队列大小为-->"+threadSize);

}

executor.shutdown();

}

publicstaticvoidmain(String[]args)throwsInterruptedException{

ArrayBlockingQueuequeue=newArrayBlockingQueue(4);//固定为4的线程队列

ThreadPoolExecutorexecutor=newThreadPoolExecutor(2,6,1,TimeUnit.DAYS,queue);

for(inti=0;i<11;i++){

executor.execute(newThread(newThreadPoolTest(),"TestThread".concat(""+i)));

intthreadSize=queue.size();

System.out.println("线程队列大小为-->"+threadSize);

}

executor.shutdown();

} 输出结果:

线程队列大小为-->0

线程名称:pool-1-thread-1

线程队列大小为-->0

线程队列大小为-->1

线程队列大小为-->2

线程队列大小为-->3

线程队列大小为-->4

线程名称:pool-1-thread-2

线程队列大小为-->4

线程名称:pool-1-thread-3

线程队列大小为-->4

线程名称:pool-1-thread-4

线程队列大小为-->4

线程名称:pool-1-thread-5

线程队列大小为-->4

线程名称:pool-1-thread-6

Exception in thread "main" java.util.concurrent.RejectedExecutionException

at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor.reject(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor.execute(Unknown Source)

at ths.ThreadPoolTest.main(ThreadPoolTest.java:30)

线程名称:pool-1-thread-1

线程名称:pool-1-thread-3

线程名称:pool-1-thread-2

线程名称:pool-1-thread-4

很明显,抛RejectedExecutionException异常了,被拒绝策略拒绝了,这就说明线程超出了线程池的总容量(线程队列大小+最大线程数)。

点击复制链接 与好友分享!回本站首页
上一篇:基本数据类型在内存中如何存放
下一篇:用二进制如何表示浮点型数值
相关文章
图文推荐
文章
推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站