一、为什么需要线程池
二、工作原理
三、线程池的分类
四、线程池的生命周期
五、阻塞对列
六、线程池关闭
-------------------------------------------------------------------------------------------------------------------------------
一、为什么需要线程池
在实际使用中,线程是很占用系统资源的,如果对线程管理不善
很容易导致系统问题。因此,在大多数并发框架中都会使用线程
池来管理线程,使用线程池管理线程主要有如下好处:
– 1、使用线程池可以重复利用已有的线程继续执行任务,避免线程在创建和
销毁时造成的消耗
– 2、由于没有线程创建和销毁时的消耗,可以提高系统响应速度
– 3、通过线程可以对线程进行合理的管理,根据系统的承受能力调整可运行
线程数量的大小等
二、工作原理
▪ 线程池执行所提交的任务过程:
▪ 1、先判断线程池中核心线程池所有的线程是否都在执行任务。
如果不是,则新创建一个线程执行刚提交的任务,否则,核心线
程池中所有的线程都在执行任务,则进入第2步;
▪ 2、判断当前阻塞队列是否已满,如果未满,则将提交的任务放
置在阻塞队列中;否则,则进入第3步;
▪ 3、判断线程池中所有的线程是否都在执行任务,如果没有,则
创建一个新的线程来执行任务,否则,则交给饱和策略进行处理
三、线程池的分类
四、线程池的生命周期
▪ RUNNING :能接受新提交的任务,并且也能处理阻塞队列中的任务;
▪ SHUTDOWN:关闭状态,不再接受新提交的任务,但却可以继续处理阻塞队列中已保存的任务。
▪ STOP:不能接受新任务,也不处理队列中的任务,会中断正在处理任务的线程。
▪ TIDYING:如果所有的任务都已终止了,workerCount (有效线程数) 为0,线程池进入该状态后会调用 terminated() 方法进入TERMINATED 状态。
▪ TERMINATED:在terminated() 方法执行完后进入该状态,默认terminated()方法中什么也没有做。
五、阻塞队列
1、ArrayBlockingQueue
1)Consumer.java
public class Consumer implements Runnable{
private BlockingQueue<Integer> blockingQueue;
public Consumer(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
try {
while (true){
System.out.println("取出来的因素是:"+blockingQueue.take());
}
} catch (InterruptedException e) {
System.out.println("消费者在等待新产品的时候被打断了!");
e.printStackTrace();
}
}
}
2)Producer.java
public class Producer implements Runnable {
private BlockingQueue<Integer> blockingQueue;
private static int element = 0;
public Producer(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
try {
while (element < 20){
System.out.println("将要放进去的因素是:"+element);
blockingQueue.put(element++);
}
} catch (InterruptedException e) {
System.out.println("生产者在等待空闲空间的时候被打断!");
e.printStackTrace();
}
System.out.println("生产者终止了生产过程!");
}
}
3)Mainclass.java
public class MainClass {
public static void main(String[] args) {
BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(3,true);
Producer producerPut = new Producer(blockingQueue);
Consumer consumerTake = new Consumer(blockingQueue);
// ProducerOffer producerOffer = new ProducerOffer(blockingQueue);
new Thread(producerPut).start();
new Thread(consumerTake).start();
}
}
2、DelayQueueTask.java
class DelayTask implements Delayed {
public String name;
public Long delayTime;
public TimeUnit delayTimeUnit;
public Long executeTime;//ms
DelayTask(String name, long delayTime, TimeUnit delayTimeUnit) {
this.name = name;
this.delayTime = delayTime;
this.delayTimeUnit = delayTimeUnit;
this.executeTime = System.currentTimeMillis() + delayTimeUnit.toMillis(delayTime);
}
@Override
public int compareTo(Delayed o) {
if(this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS)) {
return 1;
}else if(this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS)) {
return -1;
}
return 0;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(executeTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
}
public class DelayQueueTask {
public static void main(String[] args) {
DelayQueue<DelayTask> delayQueue = new DelayQueue<>();
delayQueue.add(new DelayTask("1",1000L,TimeUnit.MILLISECONDS));
delayQueue.add(new DelayTask("2",1000L,TimeUnit.MILLISECONDS));
delayQueue.add(new DelayTask("3",1000L,TimeUnit.MILLISECONDS));
System.out.println("delayQueue put done");
while (!delayQueue.isEmpty()){
try {
DelayTask delayTask = delayQueue.take();
System.out.println(delayTask.name + ":" + System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3、blockingqueue.priorityQueue
1)UsePriorityBlockingQueue.java
public class UsePriorityBlockingQueue {
public static void main(String[] args) throws Exception{
PriorityBlockingQueue<Task> q = new PriorityBlockingQueue<Task>();
Task t1 = new Task();
t1.setId(3);
t1.setName("id为3");
Task t2 = new Task();
t2.setId(4);
t2.setName("id为4");
Task t3 = new Task();
t3.setId(1);
t3.setName("id为1");
q.add(t1); //3
q.add(t2); //4
q.add(t3); //1
System.out.println("容器:" + q);
System.out.println(q.take().getId());
System.out.println("容器:" + q);
}
}
2)Task.java
public class Task implements Comparable<Task> {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Task task) {
return this.id > task.id ? 1 : (this.id < task.id ? -1 :0);
}
@Override
public String toString() {
return this.id + "," + this.name;
}
}
4、callable
1)MyTask.java
public class MyTask implements Callable<String> {
@Override
public String call() throws Exception {
// Thread.sleep(200);
Random random = new Random();
int i = random.nextInt(1000);
return Thread.currentThread().getName() + "---" + i + "---" + "is running!";
}
}
2)Test.java
public class Test {
public static void main(String[] args) {
//创建线程池对象
ExecutorService executorService = Executors.newFixedThreadPool(5);
//提交任务,返回一个future对象
for (int i = 0 ; i < 20 ;i++){
Future<String> future = executorService.submit(new MyTask());
try {
String s = future.get();
System.out.println(s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//关闭资源
executorService.shutdown();
}
}
5、forkJoin
1)ForkJoinPoolAction.java
/**
* 简单打印0-300的数值,用多线程实现并执行
*/
public class ForkJoinPoolAction {
public static void main(String[] args) {
PrintTask task = new PrintTask(0, 300);
//创建实例,并执行分割任务
ForkJoinPool pool = new ForkJoinPool();
pool.submit(task);
//线程阻塞,等待所有线程完成
pool.awaitQuiescence(2, TimeUnit.SECONDS);
//关闭线程池
pool.shutdown();
}
}
2)ForkJoinPoolTask.java
public class ForkJoinPoolTask {
public static void main(String[] args) throws ExecutionException, InterruptedException {
int[] arr = new int[100];
Random random = new Random();
int total = 0;
//初始化一百个数组元素
for (int i = 0,len = arr.length; i <len ; i++) {
int temp = random.nextInt(20);
//对数组元素赋值,并将数组元素的值添加到sum总和中
total = (arr[i]=temp);
System.out.println(Thread.currentThread().getName()+ "的arr[i]值:"+arr[i]+"求和:" + total);
}
System.out.println("初始化数组总合:"+total);
SumTask sumTask = new SumTask(arr,0,arr.length);
//创建一个通用池,这个是jdk1.8提供的功能
ForkJoinPool pool = ForkJoinPool.commonPool();
Future<Integer> future = pool.submit(sumTask);//提供分解的SumTask任务
System.out.println("多线程执行结果:"+future.get());
//关闭线程池
pool.shutdown();
}
}
3)PrintTask.java
public class PrintTask extends RecursiveAction {
private static final int THRESHOLD = 50;//最多只能打印50个数
private int start;
private int end;
PrintTask(int start, int end){
super();
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if(end - start < THRESHOLD){
for (int i = start; i <end ; i++) {
System.out.println(Thread.currentThread().getName()+"----i的值"+i);
}
}else {
int middle =(start + end)/2;
PrintTask left = new PrintTask(start,middle);
PrintTask right = new PrintTask(middle,end);
//并行执行两个小任务
left.fork();
right.fork();
}
}
}
4)SumTask.java
public class SumTask extends RecursiveTask<Integer> {
private static final int THRESHOLD = 20;//每个小任务,最多只累加20个数
private int array[];
private int start;
private int end;
/**
* Creates a new instance of SumTask.
* 累加从start到end的array数组
* array
* start
* end
*/
public SumTask(int[] array, int start, int end) {
super();
this.array = array;
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
int sum = 0;
//当end与start之间的差小于threshold时,开始进行实际的累加
if(end - start <THRESHOLD){
for (int i = start; i <end ; i++) {
sum += array[i];
System.out.println(Thread.currentThread().getName()+"i的值:"+array[i]+",求和:"+sum);
}
return sum;
}else {//当end与start之间的差大于threshold,即要累加的数超过20个时候,将大任务分解成小任务
int middle = (start + end)/2;
SumTask left = new SumTask(array,start,middle);
SumTask right = new SumTask(array,middle,end);
//并行执行两个小任务
left.fork();
right.fork();
//把两个小任务累加的结果合并起来
return left.join() + right.join();
}
}
}
6、thread_Pool.java
1)CachedThreadPoolDemo.java
public class CachedThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
//提交任务
for (int i = 0; i <20 ; i++) {
executorService.execute(new MyTask());
}
//关闭线程池
executorService.shutdown();
}
}
2)FixedThreadPoolDemo.java
public class FixedThreadPoolDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i <20 ; i++) {
executorService.execute(new MyTask());
}
executorService.shutdown();
}
}
3)MyTask.java
public class MyTask implements Runnable{
@Override
public void run() {
// try {
// Thread.sleep(200);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println(Thread.currentThread().getName() + "----is running");
}
}
4)SingleThreadExecutorDemo.java
public class SingleThreadExecutorDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i <30 ; i++) {
executorService.execute(new MyTask());
}
executorService.shutdown();
}
}
7、ThreadPoolExecutorDemo。javaliu
public class ThreadPoolExecutorDemo {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1,11,60L, TimeUnit.SECONDS,new ArrayBlockingQueue(5));
for (int i = 0; i < 20; i++) {
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is running! ");
}
});
}
threadPoolExecutor.shutdown();
}
}
六、线程池关闭
▪ 关闭线程池,可以通过shutdown和shutdownNow两个方法
▪ 原理:遍历线程池中的所有线程,然后依次中断
▪ 1、shutdownNow首先将线程池的状态设置为STOP,然后尝试停止所有的正在执行和未执行任务的线程,并返回等待执行任务的列表;
▪ 2、shutdown只是将线程池的状态设置为SHUTDOWN状态,然后中断所有没有正在执行任务的线程