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 ScheduledThreadPoolExecutor
extends ThreadPoolExecutor
implements 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;
} @Override
protected 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

更多教程请参考 flydean的博客

java中ThreadPool的介绍和使用的更多相关文章

  1. 【转】java中Thread类方法介绍

    原文: java中Thread类方法介绍 http://blog.csdn.net/seapeak007/article/details/53395609 这篇文章找时间分析一下!!!:http:// ...

  2. Java中包的介绍

    包的介绍: 未命名包 命名包 可以避免类名重复 为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间. 包的作用 1.把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用. 2. ...

  3. Java中BigDecimal类介绍及用法

    Java中提供了大数字(超过16位有效位)的操作类,即 java.math.BinInteger 类和 java.math.BigDecimal 类,用于高精度计算. 其中 BigInteger 类是 ...

  4. Java中RunTime类介绍

    Runtime 类代表着Java程序的运行时环境,每个Java程序都有一个Runtime实例,该类会被自动创建,我们可以通过Runtime.getRuntime() 方法来获取当前程序的Runtime ...

  5. Java中static关键字介绍

    static关键字主要有两种作用: 第一,为某特定数据类型或对象分配单一的存储空间,而与创建对象的个数无关. 第二,实现某个方法或属性与类而不是对象关联在一起 具体而言,在Java语言中,static ...

  6. java中commons-beanutils的介绍

    1.   概述 commons-beanutil开源库是apache组织的一个基础的开源库.为apache中很多类提供工具方法.学习它是学习其它开源库实现的基础. Commons-beanutil中包 ...

  7. java中commons-beanutils的介绍(转)

    1.   概述 commons-beanutil开源库是apache组织的一个基础的开源库.为apache中很多类提供工具方法.学习它是学习其它开源库实现的基础. Commons-beanutil中包 ...

  8. 15、java中的内部类介绍

    内部类顾名思义就是定义在类中的类,下面做一个简单介绍: 内部类的访问规则:1,内部类可以直接访问外部类中的成员,包括私有. 之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式 ...

  9. Java基础(40):Java中的集合介绍---Collection与Map

    集合类说明及区别Collection├List│├LinkedList│├ArrayList│└Vector│ └Stack└SetMap├Hashtable├HashMap└WeakHashMap ...

随机推荐

  1. 《快速认识 Three.js 》

    此文仅作备份之用,为了更好的阅读体验,建议访问原文链接:<Three.js - 走进3D的奇妙世界.> ,感谢原作者的好文.

  2. 手动搭建I/O网络通信框架2:Socket和ServerSocket入门实战,实现单聊

    第一章:手动搭建I/O网络通信框架1:Socket和ServerSocket入门实战,实现单聊 在第一章中运用Socket和ServerSocket简单的实现了网络通信.这一章,利用BIO编程模型进行 ...

  3. 微信小程序项目总结

    最近公司做的项目,我主要负责小程序前端页面也API数据请求页面渲染工作,因为对微信小程序的不熟悉,在做的过程中不免做了很多弯路.现在总结如下: 首先遇到的问题就是"微信小程序尺寸单位&quo ...

  4. js定义类的方法

    ECMAScript6已经支持了class,但之前版本都不支持类,但是可以通过一些方法来模拟类. js中的类,既是重点,也是难点,很多时候都感觉模棱两可. 首先强调一下js中很重要的3个知识点:thi ...

  5. python 函数--递归函数

    一.递归函数的定义:在一个函数里面调用函数本身 python限制最大层数:998层 def foo(n): print(n) n+=1 foo(n) foo(1)

  6. Linux网络安全篇,FTP服务器的架设

    一.FTP简介 FTP基于TCP协议.而且FTP服务器使用了命令通道和数据流通道两个连接.两个连接都会分别进行三次握手.在命令通道中客户端会随机取一个大于1024的端口与FTP服务器的21端口建立连接 ...

  7. MySQL学习之路3-MySQL中常用数据类型

    MySQL中常用数据类型 字符型 存储字符型数据.例如姓名,地址,电话号码等.使用引号括起来,一般使用单引号. 常用类型: char(255) 定长字符串,最大长度255个字符. varchar(25 ...

  8. Mac PyCharm之.gitignore 安装设置

    1. 首先安装.ignore 点击 PyCharm >>> Preferences 点击Plugins >>> 在搜索框输入.ignore >>> ...

  9. 【小学数学】算术口诀 独立音频MP3

    算术口诀 独立音频MP3 原文载于本人个人网站:http://www.unlimitedbladeworks.cc/writing_202004_01_sskj 特点 加法口诀 乘法口诀 独立音频 m ...

  10. AJ学IOS 之微博项目实战(3)微博主框架-UIImage防止iOS7之后自动渲染_定义分类

    AJ分享,必须精品 一:效果对比 当我们设置tabBarController的tabBarItem.image的时候,默认情况下会出现图片变成蓝色的效果,这是因为ios7之后会对图片自动渲染成蓝色 代 ...