文章目录

  • Thread Pool简介
  • Executors, Executor 和 ExecutorService
  • ThreadPoolExecutor
  • ScheduledThreadPoolExecutor
  • ForkJoinPool

java中ThreadPool的介绍和使用

Thread Pool简介

在Java中,threads是和系统的threads相对应的,用来处理一系列的系统资源。不管在windows和linux下面,能开启的线程个数都是有限的,如果你在java程序中无限制的创建thread,那么将会遇到无线程可创建的情况。

CPU的核数是有限的,如果同时有多个线程正在运行中,那么CPU将会根据线程的优先级进行轮循,给每个线程分配特定的CPU时间。所以线程也不是越多越好。

在java中,代表管理ThreadPool的接口有两个:ExecutorService和Executor。

我们运行线程的步骤一般是这样的:1. 创建一个ExecutorService。 2.将任务提交给ExecutorService。3.ExecutorService调度线程来运行任务。

画个图来表示:

下面我讲一下,怎么在java中使用ThreadPool。

Executors, Executor 和 ExecutorService

Executors 提供了一系列简便的方法,来帮助我们创建ThreadPool。

Executor接口定义了一个方法:

public interface Executor {/*** Executes the given command at some time in the future.  The command* may execute in a new thread, in a pooled thread, or in the calling* thread, at the discretion of the {@code Executor} implementation.** @param command the runnable task* @throws RejectedExecutionException if this task cannot be* accepted for execution* @throws NullPointerException if command is null*/void execute(Runnable command);
}

ExecutorService继承了Executor,提供了更多的线程池的操作。是对Executor的补充。

根据接口实现分离的原则,我们通常在java代码中使用ExecutorService或者Executor,而不是具体的实现类。

我们看下怎么通过Executors来创建一个Executor和ExecutorService:

        Executor executor = Executors.newSingleThreadExecutor();executor.execute(() -> log.info("in Executor"));ExecutorService executorService= Executors.newCachedThreadPool();executorService.submit(()->log.info("in ExecutorService"));executorService.shutdown();

关于ExecutorService的细节,我们这里就多讲了,感兴趣的朋友可以参考之前我写的ExecutorService的详细文章。

ThreadPoolExecutor

ThreadPoolExecutor是ExecutorService接口的一个实现,它可以为线程池添加更加精细的配置,具体而言它可以控制这三个参数:corePoolSize, maximumPoolSize, 和 keepAliveTime。

PoolSize就是线程池里面的线程个数,corePoolSize表示的是线程池里面初始化和保持的最小的线程个数。

如果当前等待线程太多,可以设置maximumPoolSize来提供最大的线程池个数,从而线程池会创建更多的线程以供任务执行。

keepAliveTime是多余的线程未分配任务将会等待的时间。超出该时间,线程将会被线程池回收。

我们看下怎么创建一个ThreadPoolExecutor:

        ThreadPoolExecutor threadPoolExecutor =new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());threadPoolExecutor.submit(()->log.info("submit through threadPoolExecutor"));threadPoolExecutor.shutdown();

上面的例子中我们通过ThreadPoolExecutor的构造函数来创建ThreadPoolExecutor。

通常来说Executors已经内置了ThreadPoolExecutor的很多实现,我们来看下面的例子:

ThreadPoolExecutor executor1 =(ThreadPoolExecutor) Executors.newFixedThreadPool(2);executor1.submit(() -> {Thread.sleep(1000);return null;});executor1.submit(() -> {Thread.sleep(1000);return null;});executor1.submit(() -> {Thread.sleep(1000);return null;});log.info("executor1 poolsize {}",executor1.getPoolSize());log.info("executor1 queuesize {}", executor1.getQueue().size());executor1.shutdown();

上的例子中我们Executors.newFixedThreadPool(2)来创建一个ThreadPoolExecutor。

上面的例子中我们提交了3个task。但是我们pool size只有2。所以还有一个1个不能立刻被执行,需要在queue中等待。

我们再看一个例子:

ThreadPoolExecutor executor2 =(ThreadPoolExecutor) Executors.newCachedThreadPool();executor2.submit(() -> {Thread.sleep(1000);return null;});executor2.submit(() -> {Thread.sleep(1000);return null;});executor2.submit(() -> {Thread.sleep(1000);return null;});log.info("executor2 poolsize {}", executor2.getPoolSize());log.info("executor2 queue size {}", executor2.getQueue().size());executor2.shutdown();

上面的例子中我们使用Executors.newCachedThreadPool()来创建一个ThreadPoolExecutor。 运行之后我们可以看到poolsize是3,而queue size是0。这表明newCachedThreadPool会自动增加pool size。

如果thread在60秒钟之类没有被激活,则会被收回。

这里的Queue是一个SynchronousQueue,因为插入和取出基本上是同时进行的,所以这里的queue size基本都是0.

ScheduledThreadPoolExecutor

还有个很常用的ScheduledThreadPoolExecutor,它继承自ThreadPoolExecutor, 并且实现了ScheduledExecutorService接口。

public class ScheduledThreadPoolExecutorextends ThreadPoolExecutorimplements ScheduledExecutorService

我们看下怎么使用:

ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);executor.schedule(() -> {log.info("Hello World");}, 500, TimeUnit.MILLISECONDS);

上面的例子中,我们定义了一个定时任务将会在500毫秒之后执行。

之前我们也讲到了ScheduledExecutorService还有两个非常常用的方法:

  • scheduleAtFixedRate - 以开始时间为间隔。
  • scheduleWithFixedDelay - 以结束时间为间隔。

CountDownLatch lock = new CountDownLatch(3);ScheduledExecutorService executor2 = Executors.newScheduledThreadPool(5);ScheduledFuture<?> future = executor2.scheduleAtFixedRate(() -> {log.info("in ScheduledFuture");lock.countDown();}, 500, 100, TimeUnit.MILLISECONDS);lock.await(1000, TimeUnit.MILLISECONDS);future.cancel(true);

ForkJoinPool

ForkJoinPool是在java 7 中引入的新框架,我们将会在后面的文章中详细讲解。 这里做个简单的介绍。

ForkJoinPool主要用来生成大量的任务来做算法运算。如果用线程来做的话,会消耗大量的线程。但是在fork/join框架中就不会出现这个问题。

在fork/join中,任何task都可以生成大量的子task,然后通过使用join()等待子task结束。

这里我们举一个例子:

static class TreeNode {int value;Set<TreeNode> children;TreeNode(int value, TreeNode... children) {this.value = value;this.children = Sets.newHashSet(children);}
}

定义一个TreeNode,然后遍历所有的value,将其加起来:

public  class CountingTask extends RecursiveTask<Integer> {private final TreeNode node;public CountingTask(TreeNode node) {this.node = node;}@Overrideprotected Integer compute() {return node.value + node.children.stream().map(childNode -> new CountingTask(childNode).fork()).mapToInt(ForkJoinTask::join).sum();}
}

下面是调用的代码:

    public static void main(String[] args) {TreeNode tree = new TreeNode(5,new TreeNode(3), new TreeNode(2,new TreeNode(2), new TreeNode(8)));ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();int sum = forkJoinPool.invoke(new CountingTask(tree));}

本文的例子请参考https://github.com/ddean2009/learn-java-concurrency/tree/master/threadPool

更多精彩内容且看:

  • 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
  • Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
  • Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
  • java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程

更多教程请参考 flydean的博客

java中ThreadPool的介绍和使用相关推荐

  1. Java中BigDecimal类介绍及用法

    Java中BigDecimal类介绍及用法 Java中提供了大数字(超过16位有效位)的操作类,即 java.math.BinInteger 类和 java.math.BigDecimal 类,用于高 ...

  2. Java中List集合介绍(炒鸡详细呦)

    Java中List集合介绍 文章目录 Java中List集合介绍 1,Java集合介绍 2,List介绍 2.1 ArrayList集合 2.2 LinkedList集合 3,List常用方法 3.1 ...

  3. javac 与java_javac中使用-d,以及javac / java中使用-cp介绍

    javac中使用-d,以及javac / java中使用-cp介绍 发布时间:2019-01-15 20:39, 浏览次数:555 , 标签: javac java cp * 一般生成把java编译成 ...

  4. java中Cookie详细介绍

    Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是 ...

  5. scheduledexecutorservice 的使用_java中ThreadPool的介绍和使用

    Thread Pool简介 在Java中,threads是和系统的threads相对应的,用来处理一系列的系统资源.不管在windows和linux下面,能开启的线程个数都是有限的,如果你在java程 ...

  6. java try catch_异常处理,JAVA中异常处理的介绍

    异常处理的介绍 在Java程序的运行过程中,如果Java虚拟机检测出一个无法执行的操作,就会产生运行时错误(runtime error) 在Java中,运行时错误会作为异常来抛出. 抛出的异常是一个对 ...

  7. Java中所有锁介绍

    在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 1.公平锁 / 非公平锁 2.可重入锁 / 不可重入锁 3.独享锁 / 共享锁 4.互斥锁 / 读 ...

  8. java中锁的介绍及运用

    个人免费资源分享网站:http://xiaocaoshare.com/ 1.悲观锁和乐观锁 对于同一个数据的并发操作,悲观锁认为自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加 ...

  9. java中事务的介绍

    2019独角兽企业重金招聘Python工程师标准>>> java的事务处理,如果对数据库进行多次操作,每一次的执行或步骤都是一个事务.如果数据库操作在某 一步没有执行或出现异常而导致 ...

最新文章

  1. git add 文件夹_Git的下载安装以及基本操作
  2. 北大AI公开课2019 | 商汤科技沈徽:AI创新与落地
  3. 网络编程学习笔记(ioctl操作)
  4. 如何做一场高质量的分享
  5. SpringBoot操作Kafka创建Topic、Producer、Consumer
  6. 11/100. Convert BST to Greater Tree
  7. 算法6-1:哈希函数
  8. Collecting package metadata (current_repodata.json): failed(解决方案)
  9. SWAT入门小问题的解决
  10. south的使用总结
  11. 【成功的忙人】在北京30套房的小哥:人一闲,就废了!
  12. 7月22日 暑假的一些心得记录
  13. 图片尺寸怎么修改?分享2种方法快速修改图片尺寸大小
  14. 操作系统学习笔记(五)---进程同步
  15. flink Table Api 理论篇
  16. 二叉树的中序遍历-递归和非递归算法
  17. python中字典的使用_python中的字典用法大全
  18. 论测试猿如何优雅的甩锅
  19. adb安装apk到手机
  20. 爬虫系列:读取 CSV、PDF、Word 文档

热门文章

  1. 下图为双总线结构机器的数据通路_PDPS机器人虚拟调试 弧焊仿真 第一课 弧焊项目创建...
  2. Three.js入门
  3. Spaly_Tree 模版
  4. HDU4475(找规律+预处理加速)
  5. 源码免杀-过启发式的思路
  6. kubeadm reset后安装遇到的错误:Unable to connect to the server: x509: certificate signed by unknown authority
  7. 面试官给我挖坑:a[i][j] 和 a[j][i] 有什么区别?
  8. JAVA通信编程(五)——串口通讯的补充说明
  9. 读者吐槽:Go 面试总被问到 RPC
  10. Django模型(一)