线程池之线程池说明


 一,线程池

 我们知道线程不可能无限制的创建,但是现实需求中遇到并发请求多任务的时候,会用多线程来处理,但是这么多的线程又不可能全部创建出来,这时我们就会想到线程池了,

说道线程池,它其实就是一种管理多线程一种手段。下面的代码是描述要测试的使用的代码,

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 {
	/**
	 * 一个阻塞队列
	*/
	BlockingQueue<Runnable> queues=new LinkedBlockingQueue<Runnable>(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<corePoolSize 时候直接执行,阻塞队列没有多余线程可放

2,当corePoolSize<threadNum<maximumPoolSize ,阻塞队列线程数量min(queueNums,threadNum-corePoolSize) 执行的线程数量为corePoolSize 

3,当threadNum>maximumPoolSize且 (threadNum-min(queueNums,threadNum-corePoolSize))<maximumPoolSize  阻塞队列线程数量min(queueNums,threadNum-corePoolSize)   执行的线程数量为threadNum-min(queueNums,threadNum-corePoolSize)

4,当 3,当threadNum>maximumPoolSize且 (threadNum-min(queueNums,threadNum-corePoolSize))>maximumPoolSize 直接报错 抛异常

猜你喜欢

转载自584431411.iteye.com/blog/2393456