【Java实战】线程池 并发 并行 生命周期(详细解释)
线程池:
一种复用线程的技术
不使用线程池的问题:
用户每提出一个需求,都要创建一个新的线程。
创建线程池的方法:
JDK 5.0起提供了一个代表线程池的接口:ExecutorService。
方式一:
使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象。
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数详细解析
参数一: corePoolSize(核心线程数)
意义:线程池中保持存活的最小线程数量,即使它们处于空闲状态。
参数二: maximumPoolSize(最大线程数)
意义:线程池允许创建的最大线程数量。
参数三:keepAliveTime(线程空闲时间)
意义:当线程数超过核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。
参数四:unit(时间单位)
意义:keepAliveTime参数的时间单位。
参数五:workQueue(工作队列)
意义:用于保存等待执行的任务的阻塞队列。
参数六:threadFactory(线程工厂)
意义:用于创建新线程的工厂。
参数七:handler(拒绝策略)
意义:当线程池和工作队列都达到饱和状态时(即线程数达到maximumPoolSize且队列已满),对新任务采取的处理策略。
类比理解:
参数一 正式工:3
参数二 最大员工数:5 临时工:2
参数三四 临时工空闲多久被开除
参数五 客人排队的地方
参数六 负责招聘的hr
参数七 忙不过来怎么办?
代码演示:
public class ThreadPoolTest{public static void main(String[] args){new ThreadPoolExecutor(3,5,8,TimeUnit.SECOND,new LinkedBlockingQuene<>(),Executors.defaultThreadFactory(),new ThreadPoolExexutor.AbortPolicy());}
}
说明:
workQueue实现类:
LinkedBlockingQuene不限制大小
ArrayBlockingQuene可控制大小
线程工厂:
Executors.defaultThreadFactory()
处理策略:
ThreadPoolExexutor.AbortPolicy()
可抛出异常。
线程池的注意事项:
1.临时线程什么时候创建?
新任务提交时核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建。
2.什么时候会开始拒绝新任务?
核心线程和临时线程都在忙,任务队列也满了,新的任务过来会拒绝新的任务。
线程池处理Runnable任务
execute()方法:
线程池会自动创建一个线程池,自动执行
\\创建一个Runnable对象
public class MyRunnable implements Runnable{@Overridepublic void run(){
System.out.println(Thread.currentThread().getName());
try{
Thread.sleep(1000);
}catch(Exception e){e.printStackTrace();
}
}
}```java
public class ThreadPoolTest{public static void main(String[] args){new ThreadPoolExecutor(3,5,8,TimeUnit.SECOND,new LinkedBlockingQuene<>(),Executors.defaultThreadFactory(),new ThreadPoolExexutor.AbortPolicy());Runnable target=new MyRunnable();pool.execute(target);//自动创建一个新线程,自动执行}
}
shutdown()
等线程池的任务全部执行完毕,再关闭线程池
pool.shutdown();
shutdownNow()
立即关闭线程池
pool.shutdownNow();
线程池处理Callable方法
Future<> submit()
//定义一个任务类,实现Callable接口
public class MyCallable implement Callable<String>{
private int n;
public MyCallable(int n){
this.n=n;
}
//重写Callable的call方法
@Override
public String call() throwException{
//描述线程的任务就是返回线程执行返回的结果
int sum=0;
for(int i=0;i<=n;i++){
sum+=i;
}
return Thread.currentThraed.getName()+sum;
}}public class ThreadPoolTest{public static void main(String[] args){new ThreadPoolExecutor(3,5,8,TimeUnit.SECOND,new LinkedBlockingQuene<>(),Executors.defaultThreadFactory(),new ThreadPoolExexutor.AbortPolicy());
//创建Callable任务
Futuer<String> f1=pool.submit(new MyCallable(100)); //自动创建一个新线程,自动执行}
}
方式二:
使用**Executor(线程池工具类)**调用方法返回不同特点的线程池对象。
public class ThreadPoolTest{public static void main(String[] args){//创建固定数量线程的线程池Executor pool=Executor.newFixedThreadPool(3);}
说明:底层还是通过实现类创建的线程池对象
核心线程配置:
计算密集型任务:核心线程数量=CPU的核数+1
IO密集型任务:核心线程数量=CPU的核数×2
**CPU的核数:**ctrl alt delete调出任务管理器,性能中可查
Executors使用可能存在的陷阱
大型并发型系统环境中使用Executors如果不注意可能会出现系统风险。
并发/并行
进程:
正在运行的程序(软件)就是一个独立的进程
线程是属于进程的,一个进程中可以同时运行很多个线程。
进程中的多个线程其实都是并发和并行执行的。
并发的含义:
进程中的线程是由CPU负责调度执行的,到CPU能同时处理线程的数量有限,为了保证全部线程都能往前执行,CPU会为系统的每个线程服务,由于CPU切换的速度很快,给我们的感觉是这些线程在同时执行,这就是并发。
并行的含义
在同一个时刻上,同时有多个线程在被CPU调度执行。
思考:
多线程到底是怎么在执行?
并发和并行同时进行。
线程的生命周期
线程从生到死的过程,经历各种状态和状态转换。
Thread.State();
6种状态
New新建->start()
->Runnable可运行->执行完毕出现异常
->Teminated被终止
Blocked锁堵塞
Waiting无限等待
Timed Waiting计时等待