线程池

创建线程池:

newCachedThreadPool-----》创建一个可缓存线程池,如果线程池长度超过需要处理需要,可灵活回收空线程,若无可回收,则新建线程。

newFixedThreadPool------>创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newSchedulThreadPool----》创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor----->创建一个单线程化的线程池,它会只用唯一的工作线程来执行任务,保证所有任务按照指定顺序FIFO、LIFO,优先级执行。

Executors各个方法的弊端:

1)newFixedThreadPool和newSingleThreadExecutor:

主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。

2)newCachedThreadPool和newScheduledThreadPool:

主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。

 

corePoolSize & maximumPoolSize

当一个新任务被提交到池中,如果当前运行线程小于核心线程数(corePoolSize),即使当前有空闲线程,也会新建一个线程来处理新提交的任务;如果当前运行线程数大于核心线程数(corePoolSize)并小于最大线程数(maximumPoolSize),只有当等待队列已满的情况下才会新建线程。

等待队列

任何阻塞队列(BlockingQueue)都可以用来转移或保存提交的任务,线程池大小和阻塞队列相互约束线程池:

  1. 如果运行线程数小于corePoolSize,提交新任务时就会新建一个线程来运行;

  2. 如果运行线程数大于或等于corePoolSize,新提交的任务就会入列等待;如果队列已满,并且运行线程数小于maximumPoolSize,也将会新建一个线程来运行;

  3. 如果线程数大于maximumPoolSize,新提交的任务将会根据拒绝策略来处理。

 

execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用 get(long timeout,Timeunit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

 

1. ‌返回值差异‌

  • ‌execute()‌:定义在Executor接口中,仅接收Runnable任务,‌无返回值‌。适用于不关心执行结果的场景。 ‌12
  • ‌submit()‌:定义在ExecutorService接口中,支持RunnableCallable任务,‌返回Future对象‌,可通过Future.get()获取任务结果或异常。 ‌13

2. ‌异常处理机制‌

  • ‌execute()‌:任务抛出异常时,异常会直接抛出到线程池的未捕获异常处理器(默认打印堆栈),可能导致线程终止。 ‌24
  • ‌submit()‌:异常会被捕获并封装到Future中,调用Future.get()时才会以ExecutionException形式重新抛出,需显式处理。 ‌23

 

Executors创建
Executors创建常见有4种类型:

 

Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待。

 

Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程。

 

Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序。

 

Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池。
 

1.FixedThreadPool(一池多线程)
创建一个固定线程数的线池,初始容量为5的线程池

 

public class fixThread {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);//设置线程初始容量为5

for (int i = 0; i < 10; i++) {
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName() + "正在执行中");
});
}


}
}

 

2.newCachedThreadPool(可缓存线程池)
创建一个可缓存线程池,它的特点是根据需求创线程数,不需要指定数量

代码如下(示例):

//可缓存线程池
public class CacheThread {
public static void main(String[] args) {

ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i <10 ; i++) {
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"正在执行中");
});
}

}
}
 

3.newSingleThreadExecutor(一池一线程)
创建一个线程的线程池,不需要指定数量

public class fixThread {
public static void main(String[] args) {

ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i <10 ; i++) {
executorService.execute(()->{
System.out.println(Thread.currentThread().getName()+"正在执行中");
});
}

}
}
 

4.newScheduledThreadPool(任务线程池)
public class fixThread {
public static void main(String[] args) {

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

for (int i = 0; i <10 ; i++) {
scheduledExecutorService.schedule(()->{
System.out.println(Thread.currentThread().getName()+"正在执行延迟任务");
},5, TimeUnit.SECONDS);
}

}

ThreadPoolExecutor
七大参数:

1,int corePoolSize, //核心线程数,线程池一直存在的线程数
2,int maximumPoolSize, //最大线程数,超过核心线程池另外运行存在的线程数
3,long keepAliveTime, //存活时间,最大线程数的不被使用的存活时间
4,TimeUnit unit,//存活单位
5,BlockingQueue<Runnable> workQueue) //工作队列
6,Executors.defaultThreadFactory()//线程工厂

7,defaultHandler 拒绝策略 任务超过线程可以处理的任务时候,采取的处理方式

public class fixThread {
public static void main(String[] args) {

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,10,5,TimeUnit.SECONDS,new ArrayBlockingQueue<>(5,true),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i <12 ; i++) {
threadPoolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName()+"执行中");
});
}

}
}

ThreadPoolExecutor 相比于其他创建线程池的优势在于,它可以通过参数来控制最大任务数和拒绝策略,让线程池的执行更加透明和可控,
 

 

posted @ 2021-04-15 10:24  KLAPT  阅读(63)  评论(0)    收藏  举报