线程池知识点-->线程池的分类、创建、参数理解、执行流程及状态等

1.基础概念

线程池是内部维护、创建、管理线程的任务空间,在期内部维护了多个线程,当没有任务时,这些线程就处于空闲状态;当有任务分配时,线程池就会分配一个空闲线程执行该任务;当有任务且所有线程都在忙时,线程池就创建一个线程去执行该任务。

2.线程池的分类

Java标准库提供的几种常用线程池,创建这些线程池的方法都被封装到Executors中。

FixedThreadPool:线程数固定的线程池,线程池中的线程数量固定,不会随着任务的增加而增加,也不会随着任务的减少而减少。适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能少地分配线程,即适用于执行长期的任务。

线程池参数:
○ 核心线程数和最大线程数一致
○ 非核心线程线程空闲存活时间,即keepAliveTime为0
○ 阻塞队列为无界队列LinkedBlockingQueue
● 工作机制:
a 提交线程任务
b 如果线程数少于核心线程,创建核心线程执行任务
c 如果线程数等于核心线程,把任务添加到LinkedBlockingQueue阻塞队列
d 如果线程执行完任务,去阻塞队列取任务,继续执行

CachedThreadPool:线程数根据任务动态调整的线程池,线程池中的线程数量可以根据需要进行动态调整,如果有空闲线程可用,则会重用空闲线程,如果没有可用线程,则会创建新的线程。适用于任务量不确定且任务执行时间较短的情况。

线程池参数:
○ 核心线程数为0
○ 最大线程数为Integer.MAX_VALUE
○ 工作队列是SynchronousQueue同步队列
○ 非核心线程空闲存活时间为60秒
● 工作机制:
a 提交线程任务
b 因为核心线程数为0,所以任务直接加到SynchronousQueue工作队列
c 判断是否有空闲线程,如果有,就去取出任务执行
d 如果没有空闲线程,就新建一个线程执行
e 执行完任务的线程,还可以存活60秒,如果在这期间,接到任务,可以继续存活下去;否则,被销毁。

SingleThreadExecutor:仅提供一个单线程的线程池,线程池中只有一个线程,所有的任务按照顺序依次执行。适用于需要保证任务按照顺序执行的情况。

线程池参数:
○ 核心线程数为1
○ 最大线程数也为1
○ 阻塞队列是LinkedBlockingQueue
○ 非核心线程空闲存活时间为0秒

ScheduledThreadPool:能实现定时、周期性任务的线程池,可以定时执行任务的线程池,可以指定任务的延迟时间和执行周期。适用于需要定时执行任务的情况。

线程池参数:
○ 最大线程数为Integer.MAX_VALUE
○ 阻塞队列是DelayedWorkQueue
○ keepAliveTime为0

3.线程池的创建与使用

3.1 线程池的重要参数

参数解释
corePoolSize(线程池核心线程数)线程池维护的最小线程数量,核心线程创建后不会被回收。
maximumPoolSize(线程池最大线程数)线程池允许创建的最大线程数量(包含核心线程数)
keepAliveTime(非核心线程存活时间)当一个可被回收的线程空闲时间大于该值时,就会被回收
TimeUnit(时间单位)keepAliveTime参数的单位,有hour,second等
BlockingQueue(阻塞工作队列)用来存储等待执行的任务
ThreadFactory(线程工厂)用于创建线程,以及自定义线程名称,需要实现ThreadFactory接口
RejectExecutionHandler(拒绝策略)当线程池内的线程耗尽,并且工作队列达到已满时,新提交的任务,将使用拒绝策略

3.2 线程池的创建

 主要通过创建一个ThreadPoolExecutor对象来创建线程池,对于具体线程池的下:

//创建固定数量的线程池,参数表示创建拥有几个线程的线程池
ExecutorService executorService = Executors.newFixedThreadPool(4);

//创建线程数根据任务动态调整的线程池
ExecutorService executorService = Executors.newCachedThreadPool();

//创建单线程的线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();

//创建周期性任务的线程池
ExecutorService executorService = Executors.newScheduledThreadPool(0);

3.3 线程池的关闭

线程池的关闭有shutdown()和shutdownNow()两个方法,他们的区别是:

  • shutdown() :等待当前正在执行的任务完成后关闭
  • shutdownNow():不论当前任务是否执行完毕,都立即关闭

3.4 线程池的常用方法

方法作用

void execute(Runnable command)

执行无返回值的线程任务
Future<T> submit(Callable<T> task)提交有返回值的线程任务
void shutdown()/shutdownNow()关闭线程池
boolean awaitTermination(long timeout, TimeUnit unit)等待线程池关闭

3.5 线程池的使用

3.5.1 FixedThreadPool的使用

//固定数目的线程池
public class Demo2 {

	public static void main(String[] args) throws InterruptedException {
		//创建固定数目的线程池(线程池中有四个线程)
		ExecutorService executorService = Executors.newFixedThreadPool(4);
		
		//提交6个线程任务
		for(int i = 0;i<6;i++) {
			executorService.execute(new Task("线程"+i));
		}
		
		//关闭线程池
		executorService.shutdown();
		
		while(!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
			System.out.println("线程池暂未关闭");
		}
		
		System.out.println("线程池关闭");
	}
}


class Task implements Runnable{

	private String taskName;
	
	public Task(String taskName) {
         this.taskName = taskName;
    }
	@Override
	public void run() {
		System.out.println("启动线程===>"+this.taskName);
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("结束线程<=="+this.taskName);
	}	
}

3.5.2 CachedThreadPool的使用

//动态数量的线程池
public class Demo3 {

	public static void main(String[] args) throws InterruptedException {
		
		ExecutorService executorService = Executors.newCachedThreadPool();
		
		//提交6个线程任务
		for(int i = 0;i<60;i++) {
			executorService.execute(new Task("线程"+i));
		}
		
		//关闭线程池
		executorService.shutdown();
		
		while(!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
			System.out.println("线程池暂未关闭");
		}
		
		System.out.println("线程池关闭");
	}
}

3.5.3 ScheduledThreadPool的使用

//周期性调度线程池
public class Demo4 {

	public static void main(String[] args) {
		
		ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
		
//		//延迟3秒执行任务,执行一次
//		System.out.println("当前时间"+LocalDateTime.now());
//		scheduledExecutorService.schedule(new Task1("任务一"), 3, TimeUnit.SECONDS);
		
//		//延迟1秒后执行任务,每隔3秒执行一次
//		System.out.println("当前时间"+LocalDateTime.now());
//		scheduledExecutorService.scheduleAtFixedRate(new Task1("任务一"), 1, 3, TimeUnit.SECONDS);
		
		//延迟1秒后执行任务,每隔4秒(延迟1秒+间隔3秒)执行一次
		System.out.println("当前时间"+LocalDateTime.now());
		scheduledExecutorService.scheduleWithFixedDelay(new Task1("任务一"), 1, 3, TimeUnit.SECONDS);
	}
}


class Task1 implements Runnable{

	private String taskName;
	
	public Task1(String taskName) {
         this.taskName = taskName;
    }
	@Override
	public void run() {
		System.out.println("启动线程===>"+this.taskName+LocalDateTime.now());
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("结束线程<=="+this.taskName);
	}	
}

3.6 线程池的执行流程

线程池的执行流程如下:

1.提交任务:将需要执行的任务提交给线程池。任务可以是实现了Runnable接口或Callable接口的对象。

2.任务队列:线程池会将提交的任务存放在一个任务队列中,等待线程池的线程来执行。

3.线程执行任务:线程池中的线程会从任务队列中取出任务,并执行任务。首先判断线程池中是否有空闲线程,如果有,则直接分配线程,执行任务;若没有,则判断核心线程数是否达到最大,若没有,则创建核心线程来执行任务;若已达最大,则判断工作队列是否已满,若未满,则将该线程任务放入工作队列,等待有线程空闲时,从工作队列一次取出任务执行;若工作队列已满,则判断是否超出最大线程数,若未超出,则创建非核心线程,若超出,则执行拒绝策略。

核心线程数:线程池中一直保持活动的线程数量,即在创建线程池时就规定的线程数量

线程池的拒绝策略:

1. AbortPolicy(默认策略):当线程池无法接受新的任务时,直接抛出RejectedExecutionException异常,阻止任务提交。

2. CallerRunsPolicy:当线程池无法接受新的任务时,由提交任务的线程(调用线程)执行该任务。这意味着任务提交线程会参与任务的执行,但会降低任务提交速度。

3. DiscardPolicy:当线程池无法接受新的任务时,直接丢弃该任务,不抛出异常,也不执行任务。

4. DiscardOldestPolicy:当线程池无法接受新的任务时,丢弃最早提交的任务(任务队列头部的任务),然后尝试再次提交新的任务。

4.完成任务:线程执行完任务后,会返回执行结果(如果任务是Callable类型),然后线程会继续从任务队列中取出任务执行,直到任务队列为空。

5.关闭线程池:当不再需要线程池时,需要手动关闭线程池。可以调用线程池的shutdown()方法来关闭线程池。关闭线程池后,线程池将不再接受新的任务,但会等待已经提交的任务执行完毕。

3.7 线程池的状态

线程池的状态主要有以下几种:

1. RUNNING:线程池处于运行状态,一旦创建线程池,它就处于运行状态,并且任务数为0。该状态的线程池会接收新任务,并处理工作队列中的任务。

  • 调用线程池的shutdown()方法,可以切换到关闭状态;
  • 调用线程池的shutdownNow()方法,可以切换到停止状态;

2. SHUTDOWN:线程池处于关闭状态,不再接受新的任务,但会继续执行已经提交的任务直到完成。

  • 当工作队列为空时,并且线程池中执行的任务也为空时,线程池进入TIDING状态

3. STOP:线程池处于停止状态,不再接受新的任务,并且会中断正在执行的任务。

  • 线程池中执行的任务为空,进入TODING状态

4. TIDYING:整理状态,线程池正在进行线程回收和资源释放的过程中,当所有任务都完成后会进入到这个状态。

  • terminated()执行完毕,进入TERMINATED状态

5. TERMINATED:终止状态,线程池已经终止,不再执行任何任务。

总结:线程池的状态会随着线程池的生命周期而变化。初始状态是RUNNING,当调用线程池的shutdown()方法时,状态会变为SHUTDOWN;当所有任务都完成后,状态会变为TIDYING,最终变为TERMINATED。

在不同的状态下,线程池对任务的处理方式也会有所不同。例如,在SHUTDOWN状态下,线程池不再接受新任务,但会继续执行已提交的任务;在STOP状态下,线程池会中断正在执行的任务,并且不再接受新任务。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值