什么是线程池
本质就是将任务放到阻塞队列里,然后线程池如果有空闲线程是就执行它
线程池就是可以复用线程的技术
JDK5起提供了代表线程池的接口:ExecutorService
线程池的好处
1.重用已经存在的线程,降低系统资源消耗。
2.减少线程创建和销毁造成的消耗
3.管控线程的并发。
4.提供一些更加强大的功能
如何得到线程池对象
方法一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程对象
方法二:使用Executors(线程池工具类)调用方法返回不同特点的线程池对象
ThreadPoolExecutor构造器线程池的核心参数
- corePoolSize(必需):核心线程数。默认情况下,核心线程会一直存活,但是当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。不能小于0
- maximumPoolSize(必需):线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。 最大数量>=核心线程数量
- keepAliveTime(必需):线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。不能小于0
- unit(必需):指定 keepAliveTime 参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。时间单位
- workQueue(必需):任务队列。通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中。其采用阻塞队列实现。不能为null
- threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。不能为null
- handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。不能为null
CorePoolSize:核心线程数,核心线程会一直存活。
maximumPoolSize:最大线程数,决定线程池最多可以创建多少线程。
keepAliveTime:空闲时间,当线程闲置超过空闲时间时就会被销毁。
unit:空闲时间的单位。
workQueue:缓冲队列
-
ArrayBlockingQueue:有界队列,有最大容量闲置。
-
LinkedBlockingQueue:*队列,不限制容量。
-
SynchronousQueue:同步队列,内部没有缓冲区。
threadFactory:设置线程池工厂方法,用来创建新的线程方法,可以对线程的属性进行定制,例如线程的group,线程名等,一般使用默认的工厂类即可。
handler:线程池满时的拒绝策略,
-
Abort:线程池满后,提交新任务时,会抛出异常,默认拒绝策略。
-
Discard:线程池满后,提交新任务时,对任务进行丢弃。
-
CallerRuns:线程池满后,提交新任务时,会直接找主线程执行提交的任务。
-
DiscardOldest:线程池满后,提交新任务时,会丢弃最早提交的任务。
volatile内存可见
线程池处理Runnable任务
7个核心参数创建线程池:3核心线程 5最大线程数量 8空闲线程的存活时间 TimeUnit.MILLISECONDS毫秒单位 new ArrayBlockingQueue<>(5)数组阻塞队列 Executors.defaultThreadFactory() 线程工程 new ThreadPoolExecutor.AbortPolicy()任务拒绝策略
ExecutorService pool = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolic3.y());
package com.lanou.pool;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
//自定义线程池对象 测试其特性
public class MyThread {
public static void main(String[] args) {
//1.创建线程池对象
/*
* public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
*/
ExecutorService pool = new ThreadPoolExecutor(3, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
//2.给任务线程池处理
Runnable target = new MyRunnable();
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
pool.execute(target);
//创建临时线程
pool.execute(target);
pool.execute(target);
//拒绝策略 不创建
pool.execute(target);
//关闭线程池()开发中不会使用
pool.shutdown();//立即关闭及时任务没有完成,丢失任务
}
}
package com.lanou.pool;
public class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 0; i<5; i++) {
System.out.println(Thread.currentThread().getName()+"输出了"+i);
}
// TODO Auto-generated method stub
try {
System.out.println(Thread.currentThread().getName()+"本任务与线程绑定了,线程睡眠");
Thread.sleep(100000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
线程池处理Callable任务
package com.lanou.demo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/*
* 实现线程程序的第三个方式,实现Callable接口方式
* 实现步骤
* 工厂类 Executors静态方法newFixedThreadPool方法,创建线程池对象
* 线程池对象ExecutorService接口实现类,调用方法submit提交线程任务
* submit(Callable c)
*/
public class Demo {
public static void main(String[] args)throws Exception {
ExecutorService es = Executors.newFixedThreadPool(2);
//submit方法提交线程任务,返回 Future接口实现类的对象
Future<String> result = es.submit(new ThreadPoolCallable()); // 返回的Future表示线程执行的结果。 submit可以传Runnable接口,也可以传Callable接口
String s = result.get(); // 从Future中获取结果。
System.out.println(s);
es.shutdown(); // 关闭线程池。 (不经常用)
}
}
package com.lanou.demo;
/*
* Callable 接口的实现类,作为线程提交任务出现
* 使用方法返回值
*/
import java.util.concurrent.Callable;
public class ThreadPoolCallable implements Callable<String>{ // 实现Callable接口
public String call(){ // 重写call方法。 可以有返回值
return "abc"; // 可以有返回值。 线程池中用Future接口实现类接收结果。
}
}
Callable接口实现多线程(未使用线程池):
CallableTest.java:
package com.lanou.juc;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
class MyCall implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName()+" Come in call");
//睡5秒
TimeUnit.SECONDS.sleep(5);
//返回200的状态码
return 200;
}
}
public class CallableTest {
public static void main(String[] args) throws InterruptedException, ExecutionException {
//创建MyThread对象
MyCall myCall = new MyCall();
//创建未来任务对象
FutureTask<Integer> futureTask = new FutureTask<>(myCall); // FutureTask实现了Future接口和Runnable接口,是Callable与Runnable之间的桥梁
//创建处理未来任务的线程(多线程)
new Thread(futureTask, "未来任务名").start();
System.out.println(Thread.currentThread().getName()+"主线程继续");
//获取未来任务的结果(Callable的返回值)
Integer result = futureTask.get(); // get()方法会阻塞当前线程
System.out.println(result);
Integer result2 = futureTask.get(); // 多次调用get()并不会重新执行耗时的未来任务
System.out.println(result2);
}
}
Executors得到线程池对象的常用方法
注意:Executors的底层也是基于线程池的实现类ThreadPoolExcutor创建线程池对象的.
package com.lanou.pool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
public static void main(String[] args) {
//1.创建固定线程数据的线程池
/*
* public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());/
*/
ExecutorService pool = Executors.newFixedThreadPool(3);//固定几个线程
pool.execute(new MyRunnable());
pool.execute(new MyRunnable());
pool.execute(new MyRunnable());
pool.execute(new MyRunnable());//已经没有多余线程
}
}
package com.lanou.pool;
public class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 0; i<5; i++) {
System.out.println(Thread.currentThread().getName()+"输出了"+i);
}
// TODO Auto-generated method stub
try {
System.out.println(Thread.currentThread().getName()+"本任务与线程绑定了,线程睡眠");
Thread.sleep(100000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Executors使用可能存在陷阱
阿里巴巴开发手册不允许使用