java 线程池 详解

版权声明:本文为博主原创文章,转载注明出处。有需要请联系[email protected] https://blog.csdn.net/weixin_42749765/article/details/82898348

实例1:

package com.test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class threadPoolTest {
     public static void main(String[] args) {   
         //创建线程池 核心数量5个 最大数量10个 当线程在200毫秒没内没反应关闭线程 缓存列队 5个
         ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));
         for(int i = 0; i < 15; i++){
             MyTask myTask = new MyTask(i);
             executor.execute(myTask);
             System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
             executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());
         }
         executor.shutdown();
     }
}

package com.test;

public class MyTask implements Runnable {
    private int taskNum;
     
    public MyTask(int num) {
        this.taskNum = num;
    }
     
    @SuppressWarnings("static-access")
    @Override
    public void run() {
        System.out.println("正在执行任务"+taskNum);
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("任务: "+taskNum+"已经执行完毕");
    }
}

 

日志

正在执行任务0
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务1
线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务2
线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务3
线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务4
线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
线程池中线程数目:6,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
线程池中线程数目:7,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务10
正在执行任务11
正在执行任务12
线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
线程池中线程数目:9,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务13
线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务14
任务: 0已经执行完毕
正在执行任务5
任务: 4已经执行完毕
任务: 3已经执行完毕
正在执行任务7
任务: 2已经执行完毕
任务: 1已经执行完毕
正在执行任务9
正在执行任务8
正在执行任务6
任务: 11已经执行完毕
任务: 13已经执行完毕
任务: 10已经执行完毕
任务: 12已经执行完毕
任务: 14已经执行完毕
任务: 5已经执行完毕
任务: 8已经执行完毕
任务: 6已经执行完毕
任务: 7已经执行完毕
任务: 9已经执行完毕

从上边看出来 线程池缓存列队中一直是5个  ,线程中一直执行的本来是5个 后来又加到了10个但是在往后就加进去了,如果出现在加的化会出现保错,大家可以把这个例子中的最大线程数减小就可以试出来了

实例2:

package com.test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * 创建线程池父类
 * @author yushen
 *
 */
public class ThreadPoolOnly {
	
	/**
	 * 创建定义线程池
	 * 
	 */
	public static ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));;
	
}




package com.test;
/**
 * 基础线程池父类
 * @author yushen
 *
 */
public class threadPoolTest extends ThreadPoolOnly{
	
	 //在线程池中执行任务
     public static void main(String[] args) {
    	 //15个客户同时发送来了请求
         for(int i = 0; i < 15; i++){
        	 //执行客户请求一
        	 FunA(i);
        	 //执行客户请求二
        	 FunB(i);
         }
         //有需要结束当前线程池
         executor.shutdown();
     }
     
     /**
      * 客户端用户请求第一个方法
      * @param i
      */
     public static void FunA(int i){
    	 MyTask myTask = new MyTask(i + "A");
         executor.execute(myTask);
         System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+  executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());
     }
     
     /**
      * 客户端用户请求第二个方法
      * @param i
      */
     public static void FunB(int i){
    	 MyTask myTask = new MyTask(i + "B");
         executor.execute(myTask);
         System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+  executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount());
     }
}





package com.test;

public class MyTask implements Runnable {
    private String taskNum;
     
    public MyTask(String num) {
        this.taskNum = num;
    }
     
    @SuppressWarnings("static-access")
	@Override
    public void run() {
        System.out.println("正在执行任务"+taskNum);
        try {
            Thread.currentThread().sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("任务: "+taskNum+"已经执行完毕");
    }
}

日志:

正在执行任务0A
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务0B
线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务1A
线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务1B
线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0
正在执行任务2A
线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
线程池中线程数目:6,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务5A
线程池中线程数目:7,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务5B
线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务6A
线程池中线程数目:9,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务6B
线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务7A
Exception in thread "main" java.util.concurrent.RejectedExecutionException
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1760)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:767)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:658)
	at com.test.threadPoolTest.FunB(threadPoolTest.java:38)
	at com.test.threadPoolTest.main(threadPoolTest.java:16)
任务: 0A已经执行完毕
任务: 2A已经执行完毕
任务: 1A已经执行完毕
正在执行任务3B
任务: 0B已经执行完毕
正在执行任务4A
任务: 1B已经执行完毕
正在执行任务4B
任务: 5A已经执行完毕
任务: 5B已经执行完毕
任务: 7A已经执行完毕
任务: 6B已经执行完毕
任务: 6A已经执行完毕
正在执行任务2B
正在执行任务3A
任务: 3B已经执行完毕
任务: 4B已经执行完毕
任务: 2B已经执行完毕
任务: 4A已经执行完毕
任务: 3A已经执行完毕

案例分析:

当我们的线程数量达到最大上限并且项目的缓存列队也达到上线 所以系统返回异常并且新添加的任务被拒绝了。这种情况,可以调整一下线程池的策略

handler有四个选择:
ThreadPoolExecutor.AbortPolicy() //缺省策略//抛出java.util.concurrent.RejectedExecutionException异常
ThreadPoolExecutor.CallerRunsPolicy()//重试添加当前的任务,他会自动重复调用execute()方法
ThreadPoolExecutor.DiscardOldestPolicy()  //抛弃旧的任务
ThreadPoolExecutor.DiscardPolicy()  //抛弃当前的任务
所以你根据情况,调整,即

package com.test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 创建线程池父类
 * 
 * @author yushen
 * 
 */
public class ThreadPoolOnly {
	/**
	 * 创建定义线程池
	 * 
	 */
	public static ThreadPoolExecutor executor = null;

	public static ThreadPoolExecutor RunThreadPool() {
		// 实例化线程池
		executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5));
		// 设置线程池拒绝返回策略 这个横重要
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		System.out.println("启动线程池!");
		return executor;
	}
}

或者,采用无界队列,也就不会出现任务满的情况了
即,把queue换成LinkedBlockingQueue,不过这种情况,你的最大线程数就没意义了,只会保持核心线程数在运行

案例三:

package com.test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 创建线程池父类
 * 
 * @author yushen
 * 
 */
public class ThreadPoolOnly {
	/**
	 * 创建定义线程池
	 * 
	 */
	public static ThreadPoolExecutor executor = null;

	public static ThreadPoolExecutor RunThreadPool() {
		// 实例化线程池
		executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5));
		// 设置线程池拒绝返回策略
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		System.out.println("启动线程池!");
		return executor;
	}
}





package com.test;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 基础线程池父类
 * 
 * @author yushen
 * 
 */
public class threadPoolTest {

	// 模拟实战项目中的线程池状态
	public static void main(String[] args) throws InterruptedException {//用main 模拟tomcat servlet 容器
		// 服务器 启动
		//servlet 启动 
		//开始初始化线程池
		ThreadPoolExecutor executor = new ThreadPoolOnly().RunThreadPool();

		
		// 15个客户同时发送来了请求
		for (int i = 0; i < 15; i++) {
				// 执行客户请求一
				new CFunA().FunA(i);
				// 执行客户请求二
				new CFunB().FunB(i);
		}
		
		//等待十秒
		Thread.sleep(10000);
        System.out.println("我刚歇了了十秒后来用户访问信息了!");
		
		// 一分钟后 又有10个客户同时发送来了请求
		for (int i = 0; i < 20; i++) {
			// 执行客户请求一
			new CFunA().FunA(i);
			// 执行客户请求二
			new CFunB().FunB(i);
		}
		//服务器关闭 挂壁servlet 并且关闭 线程池 //跟随servlet 的生命周期结束 顺便了结了线程池
		//executor.shutdown();
	}

}





package com.test;

/**
 * 客户端用户请求第二个方法
 * 
 * @author yushen
 * 
 */
public class CFunB extends ThreadPoolOnly {
	public void FunB(int i) {
		MyTask myTask = new MyTask(i + "B");
		executor.execute(myTask);
		System.out.println("线程池中线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" + executor.getQueue().size() + ",已执行玩别的任务数目:" + executor.getCompletedTaskCount());
	}
}





package com.test;

/**
 * 客户端用户请求第一个方法
 * 
 * @author yushen
 * 
 */
public class CFunA extends ThreadPoolOnly {
	public void FunA(int i) {
		MyTask myTask = new MyTask(i + "A");
		executor.execute(myTask);
		System.out.println("线程池中线程数目:" + executor.getPoolSize() + ",队列中等待执行的任务数目:" + executor.getQueue().size() + ",已执行玩别的任务数目:" + executor.getCompletedTaskCount());
	}
}






package com.test;

/**
 * 项目运行事件
 * 
 * @author yushen
 * 
 */
public class MyTask implements Runnable {
	private String taskNum;

	public MyTask(String num) {
		this.taskNum = num;
	}

	@SuppressWarnings("static-access")
	@Override
	public void run() {
		System.out.println("正在执行任务" + taskNum);
		try {
			Thread.currentThread().sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("任务: " + taskNum + "已经执行完毕");
	}
}

日志

启动线程池!
正在执行任务0A
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务0B
线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务1A
线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务1B
线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:0
正在执行任务2A
线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
线程池中线程数目:6,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
线程池中线程数目:7,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务5A
正在执行任务5B
线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务6A
线程池中线程数目:9,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务6B
线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:0
正在执行任务7B
正在执行任务7A
任务: 0A已经执行完毕
正在执行任务2B
任务: 1B已经执行完毕
正在执行任务3A
任务: 2A已经执行完毕
任务: 0B已经执行完毕
正在执行任务4A
任务: 1A已经执行完毕
正在执行任务3B
正在执行任务4B
任务: 5A已经执行完毕
任务: 7B已经执行完毕
任务: 7A已经执行完毕
任务: 6B已经执行完毕
任务: 5B已经执行完毕
任务: 6A已经执行完毕
线程池中线程数目:10,队列中等待执行的任务数目:0,已执行玩别的任务数目:6
正在执行任务8A
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:10
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:10
正在执行任务8B
正在执行任务9A
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:10
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:10
正在执行任务9B
正在执行任务10A
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:10
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:10
线程池中线程数目:10,队列中等待执行的任务数目:2,已执行玩别的任务数目:10
线程池中线程数目:10,队列中等待执行的任务数目:3,已执行玩别的任务数目:10
线程池中线程数目:10,队列中等待执行的任务数目:4,已执行玩别的任务数目:10
线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:10
正在执行任务13A
任务: 2B已经执行完毕
正在执行任务10B
任务: 4A已经执行完毕
正在执行任务11A
任务: 4B已经执行完毕
任务: 3B已经执行完毕
正在执行任务12A
任务: 3A已经执行完毕
正在执行任务11B
正在执行任务12B
任务: 8A已经执行完毕
任务: 8B已经执行完毕
任务: 10A已经执行完毕
任务: 13A已经执行完毕
任务: 9B已经执行完毕
任务: 9A已经执行完毕
线程池中线程数目:10,队列中等待执行的任务数目:0,已执行玩别的任务数目:18
正在执行任务13B
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:20
正在执行任务14A
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:20
正在执行任务14B
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:20
任务: 10B已经执行完毕
任务: 11A已经执行完毕
任务: 11B已经执行完毕
任务: 12A已经执行完毕
任务: 12B已经执行完毕
任务: 13B已经执行完毕
任务: 14A已经执行完毕
任务: 14B已经执行完毕
我刚歇了了十秒后来用户访问信息了!
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行玩别的任务数目:28
正在执行任务0A
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行玩别的任务数目:28
正在执行任务0B
线程池中线程数目:3,队列中等待执行的任务数目:0,已执行玩别的任务数目:28
正在执行任务1A
线程池中线程数目:4,队列中等待执行的任务数目:0,已执行玩别的任务数目:28
正在执行任务1B
线程池中线程数目:5,队列中等待执行的任务数目:0,已执行玩别的任务数目:28
线程池中线程数目:5,队列中等待执行的任务数目:1,已执行玩别的任务数目:28
正在执行任务2A
线程池中线程数目:5,队列中等待执行的任务数目:2,已执行玩别的任务数目:28
线程池中线程数目:5,队列中等待执行的任务数目:3,已执行玩别的任务数目:28
线程池中线程数目:5,队列中等待执行的任务数目:4,已执行玩别的任务数目:28
线程池中线程数目:5,队列中等待执行的任务数目:5,已执行玩别的任务数目:28
线程池中线程数目:6,队列中等待执行的任务数目:5,已执行玩别的任务数目:28
正在执行任务5A
线程池中线程数目:7,队列中等待执行的任务数目:5,已执行玩别的任务数目:28
正在执行任务5B
线程池中线程数目:8,队列中等待执行的任务数目:5,已执行玩别的任务数目:28
正在执行任务6A
线程池中线程数目:9,队列中等待执行的任务数目:5,已执行玩别的任务数目:28
线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:28
正在执行任务6B
正在执行任务7B
正在执行任务7A
任务: 0A已经执行完毕
正在执行任务2B
任务: 0B已经执行完毕
正在执行任务3A
任务: 1A已经执行完毕
正在执行任务3B
任务: 1B已经执行完毕
正在执行任务4A
任务: 2A已经执行完毕
正在执行任务4B
任务: 5A已经执行完毕
任务: 5B已经执行完毕
任务: 6A已经执行完毕
任务: 6B已经执行完毕
任务: 7B已经执行完毕
任务: 7A已经执行完毕
线程池中线程数目:10,队列中等待执行的任务数目:0,已执行玩别的任务数目:37
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:38
正在执行任务8A
正在执行任务8B
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:38
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:38
正在执行任务9A
正在执行任务9B
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:38
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:38
正在执行任务10A
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:38
线程池中线程数目:10,队列中等待执行的任务数目:2,已执行玩别的任务数目:38
线程池中线程数目:10,队列中等待执行的任务数目:3,已执行玩别的任务数目:38
线程池中线程数目:10,队列中等待执行的任务数目:4,已执行玩别的任务数目:38
线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:38
正在执行任务13A
任务: 2B已经执行完毕
正在执行任务10B
任务: 3B已经执行完毕
任务: 3A已经执行完毕
任务: 4A已经执行完毕
正在执行任务11B
正在执行任务11A
正在执行任务12A
任务: 4B已经执行完毕
正在执行任务12B
任务: 8B已经执行完毕
任务: 8A已经执行完毕
任务: 13A已经执行完毕
线程池中线程数目:10,队列中等待执行的任务数目:0,已执行玩别的任务数目:45
任务: 9B已经执行完毕
任务: 9A已经执行完毕
任务: 10A已经执行完毕
正在执行任务13B
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:45
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:48
正在执行任务14A
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:48
正在执行任务14B
正在执行任务15A
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:48
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:48
正在执行任务15B
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:48
线程池中线程数目:10,队列中等待执行的任务数目:2,已执行玩别的任务数目:48
线程池中线程数目:10,队列中等待执行的任务数目:3,已执行玩别的任务数目:48
线程池中线程数目:10,队列中等待执行的任务数目:4,已执行玩别的任务数目:48
线程池中线程数目:10,队列中等待执行的任务数目:5,已执行玩别的任务数目:48
正在执行任务18B
任务: 10B已经执行完毕
正在执行任务16A
任务: 11B已经执行完毕
任务: 12A已经执行完毕
任务: 11A已经执行完毕
正在执行任务17A
正在执行任务16B
正在执行任务17B
任务: 12B已经执行完毕
正在执行任务18A
任务: 14B已经执行完毕
任务: 13B已经执行完毕
任务: 14A已经执行完毕
任务: 15A已经执行完毕
任务: 15B已经执行完毕
任务: 18B已经执行完毕
线程池中线程数目:10,队列中等待执行的任务数目:0,已执行玩别的任务数目:58
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:58
正在执行任务19A
正在执行任务19B
线程池中线程数目:10,队列中等待执行的任务数目:1,已执行玩别的任务数目:58
任务: 16A已经执行完毕
任务: 17A已经执行完毕
任务: 16B已经执行完毕
任务: 17B已经执行完毕
任务: 18A已经执行完毕
任务: 19B已经执行完毕
任务: 19A已经执行完毕

根据上方的实例可以看出这个模拟的线程池还让我挺满意的 它实现了线程池的返回策略和服务器从启动到关闭还有中间的使用完成模拟

 

很总要的ThreadPoolExecutor类中提供的四个构造方法

public class ThreadPoolExecutor extends AbstractExecutorService {
    .....
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
            BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
 
    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
        BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
    ...
}

从上面的代码可以得知,ThreadPoolExecutor继承了AbstractExecutorService类,并提供了四个构造器,事实上,通过观察每个构造器的源码具体实现,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。

corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中;


maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;


keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;

unit:参数keepAliveTime的时间单位,有7种取值,在TimeUnit类中有7种静态属性:


TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时
TimeUnit.MINUTES;           //分钟
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒

workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:
1.ArrayBlockingQueue;
2.LinkedBlockingQueue;
3.SynchronousQueue;
ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。

任务缓存队列及排队策略

在前面我们多次提到了任务缓存队列,即workQueue,它用来存放等待执行的任务。

  workQueue的类型为BlockingQueue<Runnable>,通常可以取下面三种类型:

  1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;

  2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;

  3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。
 

threadFactory:线程工厂,主要用来创建线程;

任务拒绝策略

  当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略,handler:表示当拒绝处理任务时的策略,通常有以下四种策略:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务


ThreadPoolExecutor类中有几个非常重要的方法

execute()
submit()
shutdown()
shutdownNow()


线程池状态

volatile int runState;
static final int RUNNING    = 0;
static final int SHUTDOWN   = 1;
static final int STOP       = 2;
static final int TERMINATED = 3;

   runState表示当前线程池的状态,它是一个volatile变量用来保证线程之间的可见性;

  下面的几个static final变量表示runState可能的几个取值。

  当创建线程池后,初始时,线程池处于RUNNING状态;

  如果调用了shutdown()方法,则线程池处于SHUTDOWN状态,此时线程池不能够接受新的任务,它会等待所有任务执行完毕;

  如果调用了shutdownNow()方法,则线程池处于STOP状态,此时线程池不能接受新的任务,并且会去尝试终止正在执行的任务;

  当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。

任务的执行


private final BlockingQueue<Runnable> workQueue;              //任务缓存队列,用来存放等待执行的任务
private final ReentrantLock mainLock = new ReentrantLock();   //线程池的主要状态锁,对线程池状态(比如线程池大小
                                                              //、runState等)的改变都要使用这个锁
private final HashSet<Worker> workers = new HashSet<Worker>();  //用来存放工作集
 
private volatile long  keepAliveTime;    //线程存货时间   
private volatile boolean allowCoreThreadTimeOut;   //是否允许为核心线程设置存活时间
private volatile int   corePoolSize;     //核心池的大小(即线程池中的线程数目大于这个参数时,提交的任务会被放进任务缓存队列)
private volatile int   maximumPoolSize;   //线程池最大能容忍的线程数
 
private volatile int   poolSize;       //线程池中当前的线程数
 
private volatile RejectedExecutionHandler handler; //任务拒绝策略
 
private volatile ThreadFactory threadFactory;   //线程工厂,用来创建线程
 
private int largestPoolSize;   //用来记录线程池中曾经出现过的最大线程数
 
private long completedTaskCount;   //用来记录已经执行完毕的任务个数


这里要重点解释一下corePoolSize、maximumPoolSize、largestPoolSize三个变量

举个例子
有一个饭馆 有corePoolSize个厨师,当用餐的人越来越多 当人数超过 corePoolSize 个厨师可以完成的内容
就加入到列队等待 当 人数达到 largestPoolSize的人数级别 就启动  maximumPoolSize 个厨师  (在请几个厨师)
corePoolSize 核心线程数量
maximumPoolSize  最大线程数量
largestPoolSize  用户抵达多少人数后就触发 执行最大线程数量的一个值


项目引用实例

1.启动线程池  链接数据库  
2.然后开始 执行大量的线程
3.执行完大量线程 数据的添加修改删除 后关闭线程池 or no stop threadPool

猜你喜欢

转载自blog.csdn.net/weixin_42749765/article/details/82898348