jdk线程池的实现

作者:ThinkPet 时间:2023-07-05 18:44:35 

jdk线程池ThreadPoolExecutor的7个参数

public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue<Runnable> workQueue,
                             ThreadFactory threadFactory,
                             RejectedExecutionHandler handler) {
       if (corePoolSize < 0 ||
           maximumPoolSize <= 0 ||
           maximumPoolSize < corePoolSize ||
           keepAliveTime < 0)
           throw new IllegalArgumentException();
       if (workQueue == null || threadFactory == null || handler == null)
           throw new NullPointerException();
       this.acc = System.getSecurityManager() == null ?
               null :
               AccessController.getContext();
       this.corePoolSize = corePoolSize;
       this.maximumPoolSize = maximumPoolSize;
       this.workQueue = workQueue;
       this.keepAliveTime = unit.toNanos(keepAliveTime);
       this.threadFactory = threadFactory;
       this.handler = handler;
   }

corePoolSize

核心线程个数 ,int类型

maximunPoolSize

最大线程数 ,int类型

keepAliveTime存活时间

传long类型的值,

当线程池中的线程数大于corePoolSize核心线程个数,且线程是闲置状态,则这些空闲线程的最大存活时间是KeepAliveTime

TimeUnit

存活时间的单位, 有时/分/秒/毫秒等可选配置

workQueue

存放待执行任务的阻塞队列, 可传入

arrayBlockingQueue 基于数组的有界阻塞队列;

linkedBlockingQueue基于链表的 * 阻塞队列;

synchronousQueue最多只有1个元素的同步队列, 队列容量是1;

priorityBlockingQueue带优先级的 * 阻塞队列,出队元素是优先级最高或最低的元素;

DelayQueue 带延迟功能的 * 阻塞队列, 过期元素才会出队,队头元素是快要过期的元素.

以上几个Queue都是BlockingQueue的实现类

threadFactory

创建线程的工厂,

jdk提供了DefaultThreadFactory默认工厂,

用Executors.defaultThreadFactory()就行.

RejectedExecutionHandler拒绝策略

当队列满且线程数达到maximunPoolSize最大线程数后采取的策略, 可传入

AbortPolicy 抛出异常,这个是默认策略.

CallersRunPolicy 由调用者所在的线程执行任务

DiscardOldestPolicy 丢弃最老的任务

DiscardPolicy 丢弃新任务,不抛出异常

jdk提供的Executors快速创建线程池的用法

jdk封装了一个Executors类可以直接创建各种线程池,

用法形如

ExecutorService pool = Executors.newXXXXXPool()

可以用Executors类创建业务常用的3种线程池

固定线程池

public static ExecutorService newFixedThreadPool(int nThreads) {
       return new ThreadPoolExecutor(nThreads, nThreads,
                                     0L, TimeUnit.MILLISECONDS,
                                     new LinkedBlockingQueue<Runnable>());
   }

创建一个核心线程数和最大线程数相同的线程池,都为nThreads,

且线程池的阻塞队列长度是Integer.MAX_VALUE,

且keepAliveTime=0,说明只要线程个数比核心线程个数多并且当前空闲则回收.

单线程线程池

public static ExecutorService newSingleThreadExecutor() {
       return new FinalizableDelegatedExecutorService
           (new ThreadPoolExecutor(1, 1,
                                   0L, TimeUnit.MILLISECONDS,
                                   new LinkedBlockingQueue<Runnable>()));
   }

创建一个核心线程数和最大线程数都是1的线程池,

且线程池的阻塞队列长度是Integer.MAX_VALUE,

且keepAliveTime=0,说明只要线程个数比核心线程个数多并且当前空闲则回收.

已缓存的线程池

public static ExecutorService newCachedThreadPool() {
       return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                     60L, TimeUnit.SECONDS,
                                     new SynchronousQueue<Runnable>());
   }

创建一个按需创建线程的线程池,初始线程个数为0,最多线程个数为

Integer.MAX_VALUE,并且阻塞队列为同步队列.

keepAliveTime=60,说明当前线程在60s内空闲则回收.

CachedThreadPool的特殊之处在于,加入同步队列的任务会被马上执行,同步队列里边最多只有1个任务.

使用创建好的ExecutorService 线程池执行异步任务

jdk线程池的实现

submit操作

提交一个任务, 任务参数可以是 Runnable实现类 或 Callable 实现类.

返回的类型是Future 表示异步计算的结果, 可以用future.get()方法拿到数据.

shutdown操作

调用shutdown方法后,线程池就不会再接受新的任务了,但是工作队列里边的任务还是要执行的, 该方法会立刻返回,不等待队列任务完成再返回.

使用线程池的情况下当程序结束时记得调用shutdown关闭线程池, 如果不关闭线程池,则会导致 线程池资源一直不被释放.

shutdownNow操作

调用shutdownNow方法后,线程池就不会再接受新的任务了,并且会丢弃工作队列里边的任务,正在执行的任务会被中断,该方法会立刻返回,并不等待激活的任务执行完成. 返回值为这时候队列里面被丢弃的任务列表.

awaitTermination操作

当线程调用awaitTermination方法后,当前线程会被阻塞, 直到线程池状态变为TERMINATED 才返回,或者等待时间超时才返回.

案例1-测试FixedThreadPool执行CallableTask任务

package cn.demo;

import cn.hutool.core.util.RandomUtil;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ExecutorTestsForCallableTask {

public static void main(String[] args) throws ExecutionException, InterruptedException {
       String res1 = "";
       String res2 = "";
       String res3 = "";
       String res4 = "";

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);

//submit 提交4个任务, 实际执行时,任务是并发执行的,执行顺序不固定
       Future<String> submit1 = fixedThreadPool.submit(
               new TestCallableTask(RandomUtil.randomInt(30,1000),"t1"));
       Future<String> submit2 = fixedThreadPool.submit(
               new TestCallableTask(RandomUtil.randomInt(100,400),"t2"));
       Future<String> submit3 = fixedThreadPool.submit(
               new TestCallableTask(RandomUtil.randomInt(30,350),"t3"));
       Future<String> submit4 = fixedThreadPool.submit(
               new TestCallableTask(RandomUtil.randomInt(310,500),"t4"));

res1 = submit1.get();
       System.out.println(res1);
       res2 = submit2.get();
       System.out.println(res2);
       res3 = submit3.get();
       System.out.println(res3);
       res4 = submit4.get();
       System.out.println(res4);

fixedThreadPool.shutdown();
   }
}
package cn.demo;

import cn.hutool.core.util.RandomUtil;

import java.time.LocalDateTime;
import java.util.concurrent.Callable;

public class TestCallableTask implements Callable<String> {

private int testIntVal;
   private String taskSeq;

public TestCallableTask(int testIntVal, String taskSeq) {
       this.testIntVal = testIntVal;
       this.taskSeq = taskSeq;
   }

@Override
   public  String call() throws Exception {
       String s = LocalDateTime.now().toString();
       System.out.println(s+"->"+taskSeq+" run ....");

int i = testIntVal;
       System.out.println(i);

try {
           Thread.sleep(RandomUtil.randomInt(100,300));
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

if (i>300){
           return "300more";
       }else {
           return "300less";
       }
   }
}

案例2-测试FixedThreadPool执行RunnableTask任务

package cn.demo;

import java.util.concurrent.*;

public class ExecutorTestsForRunnableTask {

public static void main(String[] args) throws ExecutionException, InterruptedException {

String res1 = "";
       String res2 = "";
       String res3 = "";
       String res4 = "";
       ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);

//submit 提交4个任务, 实际执行时,任务是并发执行的,执行顺序不固定
       Task1Param task1Param = new Task1Param();
       task1Param.setUrl("f23r3r");
       task1Param.setName("1heg43t34t34t");
       Future<String> stringFuture = fixedThreadPool.submit(
           new TestTask1Runnable(task1Param), "success1 ok");

Task1Param t2 = new Task1Param();
       t2.setUrl("gnsg2323");
       t2.setName("2wwswer2r1asdaaws");
       Future<String> f2 = fixedThreadPool.submit(new TestTask1Runnable(t2), "success2 ok");

Task1Param t3 = new Task1Param();
       t3.setUrl("thwasr23r");
       t3.setName("3erzawfe23rawsf");
       Future<String> f3 = fixedThreadPool.submit(new TestTask1Runnable(t3), "success3 ok");

Task1Param t4 = new Task1Param();
       t4.setUrl("mjkdsragt");
       t4.setName("4tbertydraewrsfk");
       Future<String> f4 = fixedThreadPool.submit(new TestTask1Runnable(t4), "success4 ok");

res1 = stringFuture.get();
       System.out.println(res1);
       res2 = f2.get();
       System.out.println(res2);
       res3 = f3.get();
       System.out.println(res3);
       res4 = f4.get();
       System.out.println(res4);

fixedThreadPool.shutdown();
   }
}
package cn.demo;

import cn.hutool.core.util.RandomUtil;
import java.time.LocalDateTime;

public class TestTask1Runnable implements Runnable{

private Task1Param task1Param;

public TestTask1Runnable(Task1Param task1Param) {
       this.task1Param = task1Param;
   }

@Override
   public void run() {
       try {
           Thread.sleep(RandomUtil.randomInt(200,600));
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println(task1Param.getName());
       System.out.println(task1Param.getUrl());
       String s = LocalDateTime.now().toString();
       System.out.println(s+" TestTask1Runnable run ....");
   }
}

使用自定义的ThreadPoolExecutor来执行异步任务

package cn.demo;

import cn.hutool.core.util.RandomUtil;
import java.util.concurrent.*;

public class TpeTest {

private final static ThreadPoolExecutor pool =
           new ThreadPoolExecutor(
                   1,1,
                   1L, TimeUnit.MINUTES,
                   new ArrayBlockingQueue<Runnable>(1),
                   new ThreadPoolExecutor.CallerRunsPolicy());
   public static void main(String[] args) throws ExecutionException, InterruptedException {
       Future<String> submit1 = pool.submit(
               new TestCallableTask(RandomUtil.randomInt(30,1000),"t1"));
       Future<String> submit2 = pool.submit(
               new TestCallableTask(RandomUtil.randomInt(100,400),"t2"));
       Future<String> submit3 = pool.submit(
               new TestCallableTask(RandomUtil.randomInt(30,350),"t3"));
       Future<String> submit4 = pool.submit(
               new TestCallableTask(RandomUtil.randomInt(310,500),"t4"));
       System.out.println("task1-"+submit1.get());
       System.out.println("task2-"+submit2.get());
       System.out.println("task3-"+submit3.get());
       System.out.println("task4-"+submit4.get());

pool.shutdown();
   }
}

线程池使用FutureTask时需要注意的事情

线程池使用FutureTask时,如果把拒绝策略设置为 DiscardPolicy 和 DiscardOldestPolicy,并且在被拒绝的任务的Future对象上调用了无参get方法,那么调用线程会一直被阻塞.

如上面的代码,如果把CallerRunsPolicy替换成 DiscardPolicy 或 DiscardOldestPolicy ,就会导致任务一直被阻塞,一直无法取到future.get()的值.

来源:https://blog.csdn.net/ThinkPet/article/details/129824091

标签:jdk,线程池
0
投稿

猜你喜欢

  • Java抛出异常与自定义异常类应用示例

    2022-10-23 01:58:52
  • SpringBoot java-jar命令行启动原理解析

    2022-02-02 10:32:22
  • 深入理解 Java、Kotlin、Go 的线程和协程

    2022-05-04 12:39:14
  • JVM代码缓存区CodeCache原理及用法解析

    2023-08-09 06:02:29
  • Android图像处理之绘制圆形、三角形及扇形的头像

    2022-10-13 14:01:48
  • opencv配置的完整步骤(win10+VS2015+OpenCV3.1.0)

    2023-06-28 14:55:19
  • MyBatis学习教程(五)-实现关联表查询方法详解

    2021-06-23 21:04:04
  • spring boot 加载web容器tomcat流程源码分析

    2021-12-05 14:48:38
  • Java使用Log4j记录日志的方法详解

    2022-09-19 01:09:50
  • java GUI实现学生图书管理简单实例

    2023-11-11 05:00:05
  • Jsoup获取全国地区数据属性值(省市县镇村)

    2023-12-08 01:27:25
  • JAVA swing布局管理器实例解析

    2022-01-11 05:05:15
  • Android ViewPager无限循环实现底部小圆点动态滑动

    2022-03-21 11:04:28
  • Android布局——Preference自定义layout的方法

    2022-05-27 04:13:13
  • java实现分页显示效果

    2021-12-29 20:17:43
  • Java堆内存又溢出了!教你一招必杀技(推荐)

    2022-09-22 06:32:55
  • C# 循环判断会进来几次的实现代码

    2021-12-27 15:10:51
  • 使用java基础类实现zip压缩和zip解压工具类分享

    2021-11-23 08:03:41
  • java Springboot实现多文件上传功能

    2023-11-09 04:31:32
  • C#预处理指令之#line,#pragma warning 详细解析

    2021-05-26 22:09:06
  • asp之家 软件编程 m.aspxhome.com