jdk线程池的实现

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 线程池执行异步任务

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()的值.

到此这篇关于jdk线程池的实现的文章就介绍到这了,更多相关jdk线程池内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java手写线程池之向JDK线程池进发

    目录 前言 JDK线程池一瞥 自己动手实现线程池 线程池参数介绍 实现Runnable 实现Callable 拒绝策略的实现 线程池关闭实现 工作线程的工作实现 线程池实现的BUG 完整代码 线程池测试 总结 前言 在前面的文章自己动手写乞丐版线程池中,我们写了一个非常简单的线程池实现,这个只是一个非常简单的实现,在本篇文章当中我们将要实现一个和JDK内部实现的线程池非常相似的线程池. JDK线程池一瞥 我们首先看一个JDK给我们提供的线程池ThreadPoolExecutor的构造函数的参数:

  • 一篇文章彻底搞懂jdk8线程池

    这可能是最简短的线程池分析文章了. 顶层设计,定义执行接口 Interface Executor(){ void execute(Runnable command); } ExecutorService,定义控制接口 interface ExecutorService extends Executor{ } 抽象实现ExecutorService中的大部分方法 abstract class AbstractExecutorService implements ExecutorService{ /

  • Spring 与 JDK 线程池的简单使用示例详解

    1.配置自定义共享线程池(Spring线程池) @Configuration @EnableAsync public class ThreadPoolConfig{ //主要任务的调度,计划执行 @Bean("taskScheduler") public Executor createScheduler(){ // 创建一个线程池对象 ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); // 定义一个线程

  • JDK线程池和Spring线程池的使用实例解析

    这篇文章主要介绍了JDK线程池和Spring线程池的使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 JDK线程池和Spring线程池实例,异步调用,可以直接使用 (1)JDK线程池的使用,此处采用单例的方式提供,见示例: public class ThreadPoolUtil { private static int corePoolSize = 5; private static int maximumPoolSize = 10;

  • jdk自带线程池实例详解

    二.简介 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力,但频繁的创建线程的开销是很大的,那么如何来减少这部分的开销了,那么就要考虑使用线程池了.线程池就是一个线程的容器,每次只执行额定数量的线程,线程池就是用来管理这些额定数量的线程. 三.涉及线程池的类结构图 其中供我们使用的,主要是ThreadPoolExecutor类. 四.如何创建线程池 我们创建线程池一般有以下几种方法: 1.使用Executors工厂类 Executor

  • Tomcat修正JDK原生线程池bug的实现原理

    为提高处理能力和并发度,Web容器一般会把处理请求的任务放到线程池,而JDK的原生线程池先天适合CPU密集型任务,于是Tomcat改造之. Tomcat 线程池原理 其实ThreadPoolExecutor的参数主要有如下关键点: 限制线程个数 限制队列长度 而Tomcat对这俩资源都需要限制,否则高并发下CPU.内存都有被耗尽可能. 因此Tomcat的线程池传参: // 定制的任务队列 taskqueue = new TaskQueue(maxQueueSize); // 定制的线程工厂 Ta

  • jdk线程池的实现

    jdk线程池ThreadPoolExecutor的7个参数 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize &l

  • Java线程池中多余的线程是如何回收的

    最近阅读了JDK线程池ThreadPoolExecutor的源码,对线程池执行任务的流程有了大体了解,实际上这个流程也十分通俗易懂,就不再赘述了,别人写的比我好多了. 不过,我倒是对线程池是如何回收工作线程比较感兴趣,所以简单分析了一下,加深对线程池的理解吧. 那么,就以JDK1.8为例分析吧. 1.runWorker(Worker w) 工作线程启动后,就进入runWorker(Worker w)方法. 里面是一个while循环,循环判断任务是否为空,若不为空,执行任务:若取不到任务,或发生异

  • Java自定义线程池的实现示例

    目录 一.Java语言本身也是多线程,回顾Java创建线程方式如下: 二.JDK线程池工具类. 三.业界知名自定义线程池扩展使用. 一.Java语言本身也是多线程,回顾Java创建线程方式如下: 1.继承Thread类,(Thread类实现Runnable接口),来个类图加深印象. 2.实现Runnable接口实现无返回值.实现run()方法,啥时候run,黑话了. 3.实现Callable接口重写call()+FutureTask获取. public class CustomThread {

  • 关于dubbo 自定义线程池的问题

    目录 初识dubbo 一.什么是dubbo? 二.为什么要用dubbo 前言 dubbo线程池 dubbo线程池说明 自定义线程池代码实现步骤 初识dubbo 一.什么是dubbo? Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC(一种远程调用) 分布式服务框架(SOA),致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案,其实就是一种远程服务调用的分布式框架 二.为什么要用dubbo 在互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式

  • 详解Java线程池和Executor原理的分析

    详解Java线程池和Executor原理的分析 线程池作用与基本知识 在开始之前,我们先来讨论下"线程池"这个概念."线程池",顾名思义就是一个线程缓存.它是一个或者多个线程的集合,用户可以把需要执行的任务简单地扔给线程池,而不用过多的纠结与执行的细节.那么线程池有哪些作用?或者说与直接用Thread相比,有什么优势?我简单总结了以下几点: 减小线程创建和销毁带来的消耗 对于Java Thread的实现,我在前面的一篇blog中进行了分析.Java Thread与内

随机推荐