一,线程池
我们知道线程不可能无限制的创建,但是现实需求中遇到并发请求多任务的时候,会用多线程来处理,但是这么多的线程又不可能全部创建出来,这时我们就会想到线程池了,
说道线程池,它其实就是一种管理多线程一种手段。下面的代码是描述要测试的使用的代码,
package com.test.thread; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.junit.Test; public class TestThreadPool { /** * 一个阻塞队列 */ BlockingQueuequeues=new LinkedBlockingQueue (10); /** * 线程池 初始化10个线程 最大线程数量为20个,空闲时间为0L秒 */ ThreadPoolExecutor pool= new ThreadPoolExecutor(10, 20,0L,TimeUnit.MICROSECONDS,queues); /** * * @param threadNum 执行线程数量 * @throws InterruptedException */ private void testThreadPool(int threadNum)throws InterruptedException{ for(int i=1;i<=threadNum;i++){ pool.execute(new Task("aa@"+i)); } //停顿一秒钟等待线程池中初始化线程都启动 Thread.sleep(1000); //打印当前阻塞队列中有多少线程 System.out.println("此时阻塞队列有多个少任务:"+"数量->"+queues.size()+",具体线程->"+queues); System.out.println("线程池中执行的线程:"+pool.getActiveCount()); /** * shutdown方法的时候,线程池不再接收任何新任务,但此时线程池并不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。 * 在调用shutdown方法后我们可以在一个死循环里面用isTerminated方法判断是否线程池中的所有线程已经执行完毕,如果子线程都结束了,我们就可以做关闭流等后续操作了。 */ pool.shutdown(); while(true){ if(pool.isTerminated()){ System.out.println("所有任务执行完成....."); break; } Thread.sleep(200); } } /** * 测试5个线程 * @throws InterruptedException */ @Test public void testThreadPool5() throws InterruptedException { testThreadPool(5); } /** * 测试15个线程 * @throws InterruptedException */ @Test public void testThreadPool15() throws InterruptedException{ testThreadPool(15); } /** * 测试25个线程 * @throws InterruptedException */ @Test public void testThreadPool25() throws InterruptedException{ testThreadPool(25); } /** * 测试45个线程 * @throws InterruptedException */ @Test public void testThreadPool45() throws InterruptedException{ testThreadPool(45); } } class Task implements Runnable{ String name; public Task(String name) { this.name=name; } @Override public void run() { System.out.println("线程["+name+"]启动... 开始执行任务"); try { Thread.sleep(30000L); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("线程["+name+"]结束--- 完成任务"); } @Override public String toString() { return name; } }
(1)当 执行testThreadPool5()方法时候 ,这里 线程为5个数量
其中打印结果
线程[aa@2]启动... 开始执行任务 线程[aa@1]启动... 开始执行任务 线程[aa@4]启动... 开始执行任务 线程[aa@3]启动... 开始执行任务 线程[aa@5]启动... 开始执行任务 此时阻塞队列有多个少任务:数量->0,具体线程->[] 线程池中执行的线程:5 线程[aa@1]结束--- 完成任务 线程[aa@5]结束--- 完成任务 线程[aa@3]结束--- 完成任务 线程[aa@4]结束--- 完成任务 线程[aa@2]结束--- 完成任务 所有任务执行完成.....
从打印结果中我们可以看到 由于 给定的执行线程数量5 小于初始化数量10 所以 不会多余的线程放入阻塞队列中
(2)当执行testThreadPool15() 方法,这里给定执行的线程为15
其中打印结果
线程[aa@1]启动... 开始执行任务 线程[aa@3]启动... 开始执行任务 线程[aa@2]启动... 开始执行任务 线程[aa@4]启动... 开始执行任务 线程[aa@5]启动... 开始执行任务 线程[aa@6]启动... 开始执行任务 线程[aa@7]启动... 开始执行任务 线程[aa@9]启动... 开始执行任务 线程[aa@8]启动... 开始执行任务 线程[aa@10]启动... 开始执行任务 此时阻塞队列有多个少任务:数量->5,具体线程->[aa@11, aa@12, aa@13, aa@14, aa@15] 线程池中执行的线程:10 线程[aa@2]结束--- 完成任务 线程[aa@1]结束--- 完成任务 线程[aa@3]结束--- 完成任务 线程[aa@11]启动... 开始执行任务 线程[aa@6]结束--- 完成任务 线程[aa@5]结束--- 完成任务 线程[aa@15]启动... 开始执行任务 线程[aa@4]结束--- 完成任务 线程[aa@12]启动... 开始执行任务 线程[aa@13]启动... 开始执行任务 线程[aa@14]启动... 开始执行任务 线程[aa@10]结束--- 完成任务 线程[aa@7]结束--- 完成任务 线程[aa@9]结束--- 完成任务 线程[aa@8]结束--- 完成任务 线程[aa@11]结束--- 完成任务 线程[aa@15]结束--- 完成任务 线程[aa@12]结束--- 完成任务 线程[aa@13]结束--- 完成任务 线程[aa@14]结束--- 完成任务 所有任务执行完成.....
从打印结果中我们可以看到 由于 给定的执行线程数量15 大于初始化数量10 小于最大线程数量20,所以 多余的线程放入阻塞队列中为5个 随着前十个线程逐渐执行完成时, 阻塞队列中的线程也开始加入执行中,最终队列全部完成
(3)当执行testThreadPool25() 方法,这里给定执行的线程为25
其中打印结果
线程[aa@1]启动... 开始执行任务 线程[aa@4]启动... 开始执行任务 线程[aa@3]启动... 开始执行任务 线程[aa@5]启动... 开始执行任务 线程[aa@6]启动... 开始执行任务 线程[aa@2]启动... 开始执行任务 线程[aa@7]启动... 开始执行任务 线程[aa@8]启动... 开始执行任务 线程[aa@9]启动... 开始执行任务 线程[aa@10]启动... 开始执行任务 线程[aa@21]启动... 开始执行任务 线程[aa@23]启动... 开始执行任务 线程[aa@22]启动... 开始执行任务 线程[aa@24]启动... 开始执行任务 线程[aa@25]启动... 开始执行任务 此时阻塞队列有多个少任务:数量->10,具体线程->[aa@11, aa@12, aa@13, aa@14, aa@15, aa@16, aa@17, aa@18, aa@19, aa@20] 线程池中执行的线程:15 线程[aa@10]结束--- 完成任务 线程[aa@2]结束--- 完成任务 线程[aa@7]结束--- 完成任务 线程[aa@5]结束--- 完成任务 线程[aa@8]结束--- 完成任务 线程[aa@4]结束--- 完成任务 线程[aa@9]结束--- 完成任务 线程[aa@16]启动... 开始执行任务 线程[aa@1]结束--- 完成任务 线程[aa@14]启动... 开始执行任务 线程[aa@15]启动... 开始执行任务 线程[aa@13]启动... 开始执行任务 线程[aa@3]结束--- 完成任务 线程[aa@19]启动... 开始执行任务 线程[aa@12]启动... 开始执行任务 线程[aa@11]启动... 开始执行任务 线程[aa@6]结束--- 完成任务 线程[aa@20]启动... 开始执行任务 线程[aa@18]启动... 开始执行任务 线程[aa@17]启动... 开始执行任务 线程[aa@23]结束--- 完成任务 线程[aa@21]结束--- 完成任务 线程[aa@22]结束--- 完成任务 线程[aa@24]结束--- 完成任务 线程[aa@25]结束--- 完成任务 线程[aa@16]结束--- 完成任务 线程[aa@17]结束--- 完成任务 线程[aa@18]结束--- 完成任务 线程[aa@20]结束--- 完成任务 线程[aa@11]结束--- 完成任务 线程[aa@12]结束--- 完成任务 线程[aa@19]结束--- 完成任务 线程[aa@13]结束--- 完成任务 线程[aa@15]结束--- 完成任务 线程[aa@14]结束--- 完成任务 所有任务执行完成.....
从打印结果中我们可以看到 由于 给定的执行线程数量25 大于初始化数量10 大于最大线程数量20,所以 多余的线程放入阻塞队列中为10个 这是线程池中就有15个线程在执行 (这个数量小于最大数量限制20)
(3)当执行testThreadPool45() 方法,这里给定执行的线程为45
这时打印结果会报错 如下图
由于 给定的执行线程数量25 大于初始化数量10 大于最大线程数量20,而阻塞队列最多可以放置10个 这是线程池中就有25个线程执行 但是由于线程池最大数量是20 不能同时执行25个所以报错
综上所述 假设 执行线程数量 threadNum,初始化线程数量 corePoolSize, 线程最大允许执行数量maximumPoolSize ,阻塞队列容量queueNums
1,当threadNum
2,当corePoolSize
3,当threadNum>maximumPoolSize且 (threadNum-min(queueNums,threadNum-corePoolSize)) 4,当 3,当threadNum>maximumPoolSize且 (threadNum-min(queueNums,threadNum-corePoolSize))>maximumPoolSize 直接报错 抛异常