废话不多说,线上代码再做总结....
package test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import bean.MyThread1;
/**
* 类说明
*
* @author lv617
* @date 2018年7月9日 上午9:44:42
*/
public class MyThreadPool {
/*
* BlockingQueue workQueue:该线程池中的任务队列:维护着等待执行的Runnable对象
当所有的核心线程都在干活时,新添加的任务会被添加到这个队列中等待处理,如果队列满了,则新建非核心线程执行任务。
常用的workQueue类型:
SynchronousQueue:这个队列接收到任务的时候,会直接提交给线程处理,而不保留它,如果所有线程都在工作怎么办?那就新建一个线程来处理这个任务!所以为了保证不出现<线程数达到了maximumPoolSize而不能新建线程>的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大
LinkedBlockingQueue:这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize
ArrayBlockingQueue:可以限定队列的长度,接收到任务的时候,如果没有达到corePoolSize的值,则新建线程(核心线程)执行任务,如果达到了,则入队等候,如果队列已满,则新建线程(非核心线程)执行任务,又如果总线程数到了maximumPoolSize,并且队列也满了,则发生错误
DelayQueue:队列内元素必须实现Delayed接口,这就意味着你传进去的任务必须先实现Delayed接口。这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务
链接:https://www.jianshu.com/p/ae67972d1156
*/
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
//往线程池中循环提交线程
for (int i = 0; i < 10; i++) {
//创建线程类对象
MyThread1 myTask = new MyThread1(i);
//开启线程
executor.execute(myTask);
//获取线程池中线程的相应参数
System.out.println("线程池中线程数目:" +executor.getPoolSize() + ",队列中等待执行的任务数目:"+executor.getQueue().size() + ",已执行完的任务数目:"+executor.getCompletedTaskCount());
}
try {
System.out.println("==1==线程池中线程数目:" +executor.getPoolSize() + ",队列中等待执行的任务数目:"+executor.getQueue().size() + ",已执行完的任务数目:"+executor.getCompletedTaskCount());
Thread.sleep(6000);
System.out.println("==2==线程池中线程数目:" +executor.getPoolSize() + ",队列中等待执行的任务数目:"+executor.getQueue().size() + ",已执行完的任务数目:"+executor.getCompletedTaskCount());
System.out.println("执行另一批线程----");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//往线程池中循环提交线程
for (int i = 0; i < 6; i++) {
//创建线程类对象
MyThread1 myTask = new MyThread1(i);
//开启线程
executor.execute(myTask);
//获取线程池中线程的相应参数
System.out.println("2线程池中线程数目:" +executor.getPoolSize() + ",队列中等待执行的任务数目:"+executor.getQueue().size() + ",已执行完的任务数目:"+executor.getCompletedTaskCount());
}
//待线程池以及缓存队列中所有的线程任务完成后关闭线程池。
executor.shutdown();
System.out.println("关闭线程池----");
try {
Thread.sleep(20000);
System.out.println("主线程end----");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("==3==线程池中线程数目:" +executor.getPoolSize() + ",队列中等待执行的任务数目:"+executor.getQueue().size() + ",已执行完的任务数目:"+executor.getCompletedTaskCount());
}
}
线程任务类:
package bean;
/**
* 类说明
*
* @author lv617
* @date 2018年7月9日 下午1:58:39
*/
public class MyThread1 implements Runnable{
private int num;
public MyThread1() {
super();
// TODO Auto-generated constructor stub
}
public MyThread1(int num) {
super();
this.num = num;
// TODO Auto-generated constructor stub
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("正在执行task " + num);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task " + num + "执行完毕");
}
}
控制台打印结果:
正在执行task 0
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行完的任务数目:0
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行完的任务数目:0
正在执行task 1
线程池中线程数目:3,队列中等待执行的任务数目:0,已执行完的任务数目:0
正在执行task 2
线程池中线程数目:4,队列中等待执行的任务数目:0,已执行完的任务数目:0
正在执行task 3
线程池中线程数目:5,队列中等待执行的任务数目:0,已执行完的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:1,已执行完的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:2,已执行完的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:3,已执行完的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:4,已执行完的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:5,已执行完的任务数目:0
==1==线程池中线程数目:5,队列中等待执行的任务数目:5,已执行完的任务数目:0
正在执行task 4
task 0执行完毕
正在执行task 5
task 1执行完毕
task 2执行完毕
task 3执行完毕
正在执行task 7
正在执行task 6
正在执行task 8
task 4执行完毕
正在执行task 9
==2==线程池中线程数目:5,队列中等待执行的任务数目:0,已执行完的任务数目:5
执行另一批线程----
2线程池中线程数目:5,队列中等待执行的任务数目:1,已执行完的任务数目:5
2线程池中线程数目:5,队列中等待执行的任务数目:2,已执行完的任务数目:5
2线程池中线程数目:5,队列中等待执行的任务数目:3,已执行完的任务数目:5
2线程池中线程数目:5,队列中等待执行的任务数目:4,已执行完的任务数目:5
2线程池中线程数目:5,队列中等待执行的任务数目:5,已执行完的任务数目:5
2线程池中线程数目:5,队列中等待执行的任务数目:6,已执行完的任务数目:5
关闭线程池----
task 5执行完毕
正在执行task 0
task 7执行完毕
task 8执行完毕
正在执行task 1
task 6执行完毕
正在执行task 2
正在执行task 3
task 9执行完毕
正在执行task 4
task 0执行完毕
正在执行task 5
task 4执行完毕
task 1执行完毕
task 3执行完毕
task 2执行完毕
task 5执行完毕
主线程end----
==3==线程池中线程数目:0,队列中等待执行的任务数目:0,已执行完的任务数目:16
总结:
1.线程池的创建最好用单例模式(饿汉式单例模式)创建;
2.线程池其实是没有必要关闭的;
executor.shutdown(); //关闭线程池
3.线程池已执行完的任务数,统计不是实时准确的,但是最终执行完所有线程后的结果是准确的;
"已执行完的任务数目:"+executor.getCompletedTaskCount();
4.比较常用的线程池队列模式是:
SynchronousQueue:这个队列接收到任务的时候,会直接提交给线程处理,而不保留它,如果所有线程都在工作怎么办?那就新建一个线程来处理这个任务!所以为了保证不出现<线程数达到了maximumPoolSize而不能新建线程>的错误,使用这个类型队列的时候,maximumPoolSize一般指定成Integer.MAX_VALUE,即无限大
LinkedBlockingQueue:这个队列接收到任务的时候,如果当前线程数小于核心线程数,则新建线程(核心线程)处理任务;如果当前线程数等于核心线程数,则进入队列等待。由于这个队列没有最大值限制,即所有超过核心线程数的任务都将被添加到队列中,这也就导致了maximumPoolSize的设定失效,因为总线程数永远不会超过corePoolSize
5.不足之处还请指出,感激不尽,欢迎指正!