线程池负责管理工作线程,包含一个等待执行的任务队列。线程池的任务队列是一个Runnable集合,工作线程负责从任务队列中取出并执行Runnable对象。

java.util.concurrent.executors 提供了 java.util.concurrent.executor 接口的一个Java实现,可以创建线程池。下面是一个简单示例:

首先创建一个Runable 类:

WorkerThread.java

package com.journaldev.threadpool;

public class WorkerThread implements Runnable {

    private String command;

    public WorkerThread(String s){

        this.command=s;

    }

    @Override

    public void run() {

        System.out.println(Thread.currentThread().getName()+" Start. Command = "+command);

        processCommand();

        System.out.println(Thread.currentThread().getName()+" End.");

    }

    private void processCommand() {

        try {

            Thread.sleep(5000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

    @Override

    public String toString(){

        return this.command;

    }

}
package com.journaldev.threadpool;

public class WorkerThread implements Runnable {

    private String command;

    public WorkerThread(String s){

        this.command=s;

    }

    @Override

    public void run() {

        System.out.println(Thread.currentThread().getName()+" Start. Command = "+command);

        processCommand();

        System.out.println(Thread.currentThread().getName()+" End.");

    }

    private void processCommand() {

        try {

            Thread.sleep(5000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

    @Override

    public String toString(){

        return this.command;

    }

}

下面是一个测试程序,从 Executors 框架中创建固定大小的线程池:

SimpleThreadPool.java

package com.journaldev.threadpool;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

public class SimpleThreadPool {

    public static void main(String[] args) {

        ExecutorService executor = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10; i++) {

            Runnable worker = new WorkerThread("" + i);

            executor.execute(worker);

          }

        executor.shutdown();

        while (!executor.isTerminated()) {

        }

        System.out.println("Finished all threads");

    }

}
 
 

在上面的程序中,我们创建了包含5个工作线程的固定大小线程池。然后,我们向线程池提交10个任务。由于线程池的大小是5,因此首先会启动5个工作线程,其他任务将进行等待。一旦有任务结束,工作线程会从等待队列中挑选下一个任务并开始执行。

以上程序的输出结果如下:

pool-1-thread-2 Start. Command = 1

pool-1-thread-4 Start. Command = 3

pool-1-thread-1 Start. Command = 0

pool-1-thread-3 Start. Command = 2

pool-1-thread-5 Start. Command = 4

pool-1-thread-4 End.

pool-1-thread-5 End.

pool-1-thread-1 End.

pool-1-thread-3 End.

pool-1-thread-3 Start. Command = 8

pool-1-thread-2 End.

pool-1-thread-2 Start. Command = 9

pool-1-thread-1 Start. Command = 7

pool-1-thread-5 Start. Command = 6

pool-1-thread-4 Start. Command = 5

pool-1-thread-2 End.

pool-1-thread-4 End.

pool-1-thread-3 End.

pool-1-thread-5 End.

pool-1-thread-1 End.

Finished all threads
 
 

从输出结果看,线程池中有五个名为“pool-1-thread-1”…“pool-1-thread-5”的工作线程负责执行提交的任务。

Executors 类使用 ExecutorService  提供了一个 ThreadPoolExecutor 的简单实现,但 ThreadPoolExecutor 提供的功能远不止这些。我们可以指定创建 ThreadPoolExecutor 实例时活跃的线程数,并且可以限制线程池的大小,还可以创建自己的 RejectedExecutionHandler 实现来处理不适合放在工作队列里的任务。

下面是一个 RejectedExecutionHandler 接口的自定义实现:

RejectedExecutionHandlerImpl.java

package com.journaldev.threadpool;

import java.util.concurrent.RejectedExecutionHandler;

import java.util.concurrent.ThreadPoolExecutor;

public class RejectedExecutionHandlerImpl implements RejectedExecutionHandler {

    @Override

    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

        System.out.println(r.toString() + " is rejected");

    }

}

ThreadPoolExecutor 提供了一些方法,可以查看执行状态、线程池大小、活动线程数和任务数。所以,我通过一个监视线程在固定间隔输出执行信息。

MyMonitorThread.java

package com.journaldev.threadpool;

import java.util.concurrent.ThreadPoolExecutor;

public class MyMonitorThread implements Runnable

{

    private ThreadPoolExecutor executor;

    private int seconds;

    private boolean run=true;

    public MyMonitorThread(ThreadPoolExecutor executor, int delay)

    {

        this.executor = executor;

        this.seconds=delay;

    }

    public void shutdown(){

        this.run=false;

    }

    @Override

    public void run()

    {

        while(run){

                System.out.println(

                    String.format("[monitor] [%d/%d] Active: %d, Completed: %d, Task: %d, isShutdown: %s, isTerminated: %s",

                        this.executor.getPoolSize(),

                        this.executor.getCorePoolSize(),

                        this.executor.getActiveCount(),

                        this.executor.getCompletedTaskCount(),

                        this.executor.getTaskCount(),

                        this.executor.isShutdown(),

                        this.executor.isTerminated()));

                try {

                    Thread.sleep(seconds*1000);

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

        }

    }

}
 
 

下面是使用 ThreadPoolExecutor 的线程池实现示例:

WorkerPool.java

package com.journaldev.threadpool;

import java.util.concurrent.ArrayBlockingQueue;

import java.util.concurrent.Executors;

import java.util.concurrent.ThreadFactory;

import java.util.concurrent.ThreadPoolExecutor;

import java.util.concurrent.TimeUnit;

public class WorkerPool {

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

        //RejectedExecutionHandler implementation

        RejectedExecutionHandlerImpl rejectionHandler = new RejectedExecutionHandlerImpl();

        //Get the ThreadFactory implementation to use

        ThreadFactory threadFactory = Executors.defaultThreadFactory();

        //creating the ThreadPoolExecutor

        ThreadPoolExecutor executorPool = new ThreadPoolExecutor(2, 4, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2), threadFactory, rejectionHandler);

        //start the monitoring thread

        MyMonitorThread monitor = new MyMonitorThread(executorPool, 3);

        Thread monitorThread = new Thread(monitor);

        monitorThread.start();

        //submit work to the thread pool

        for(int i=0; i<10; i++){

            executorPool.execute(new WorkerThread("cmd"+i));

        }

        Thread.sleep(30000);

        //shut down the pool

        executorPool.shutdown();

        //shut down the monitor thread

        Thread.sleep(5000);

        monitor.shutdown();

    }

}
 
 

请注意:在初始化 ThreadPoolExecutor 时,初始线程池大小设为2、最大值设为4、工作队列大小设为2。所以,如果当前有4个任务正在运行而此时又有新任务提交,工作队列将只存储2个任务和其他任务将交由RejectedExecutionHandlerImpl 处理。

程序执行的结果如下,确认了上面的结论:

pool-1-thread-1 Start. Command = cmd0

pool-1-thread-4 Start. Command = cmd5

cmd6 is rejected

pool-1-thread-3 Start. Command = cmd4

pool-1-thread-2 Start. Command = cmd1

cmd7 is rejected

cmd8 is rejected

cmd9 is rejected

[monitor] [0/2] Active: 4, Completed: 0, Task: 6, isShutdown: false, isTerminated: false

[monitor] [4/2] Active: 4, Completed: 0, Task: 6, isShutdown: false, isTerminated: false

pool-1-thread-4 End.

pool-1-thread-1 End.

pool-1-thread-2 End.

pool-1-thread-3 End.

pool-1-thread-1 Start. Command = cmd3

pool-1-thread-4 Start. Command = cmd2

[monitor] [4/2] Active: 2, Completed: 4, Task: 6, isShutdown: false, isTerminated: false

[monitor] [4/2] Active: 2, Completed: 4, Task: 6, isShutdown: false, isTerminated: false

pool-1-thread-1 End.

pool-1-thread-4 End.

[monitor] [4/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false

[monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false

[monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false

[monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false

[monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false

[monitor] [2/2] Active: 0, Completed: 6, Task: 6, isShutdown: false, isTerminated: false

[monitor] [0/2] Active: 0, Completed: 6, Task: 6, isShutdown: true, isTerminated: true

[monitor] [0/2] Active: 0, Completed: 6, Task: 6, isShutdown: true, isTerminated: true
 
 

请注意活跃线程、已完成线程和任务完成总数的变化。我们可以调用 shutdown() 结束所有已提交任务并终止线程池。

如果希望延迟执行或定期运行任务,那么可以使用 ScheduledThreadPoolExecutor 类。要了解更多,请参见Java Schedule Thread Pool Executor

原文链接: journaldev    翻译: ImportNew.com - 彭秦进 译文链接: http://www.importnew.com/8542.html

线程池实例:使用Executors和ThreadPoolExecutor的更多相关文章

  1. Java线程池实现原理与技术(ThreadPoolExecutor、Executors)

    本文将通过实现一个简易的线程池理解线程池的原理,以及介绍JDK中自带的线程池ThreadPoolExecutor和Executor框架. 1.无限制线程的缺陷 多线程的软件设计方法确实可以最大限度地发 ...

  2. 线程池系列一:线程池作用及Executors方法讲解

    线程池的作用: 线程池作用就是限制系统中执行线程的数量.     根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果:少了浪费了系统资源,多了造成系统拥挤效率不高.用线程池控制线程数量 ...

  3. 并发编程 13—— 线程池的使用 之 配置ThreadPoolExecutor 和 饱和策略

    Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...

  4. java 多线程:线程池的使用Executors~ExecutorService; newCachedThreadPool;newFixedThreadPool(int threadNum);ScheduledExecutorService

    1,为什么要使用线程池:Executors 系统启动一个新线程的成本是比较高的,因为它涉及与操作系统交互.在这种情形下,使用线程池可以很好地提高性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更 ...

  5. JAVA四种线程池实例

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗?   Java   1 2 3 4 5 6 7 new Thread(new Runnable() {        ...

  6. java线程池实例

    目的         了解线程池的知识后,写个线程池实例,熟悉多线程开发,建议看jdk线程池源码,跟大师比,才知道差距啊O(∩_∩)O 线程池类 package thread.pool2; impor ...

  7. Java:多线程,线程池,用Executors静态工厂生成常用线程池

    一: newSingleThreadExecutor 创建一个单线程的线程池,以无界队列方式运行.这个线程池只有一个线程在工作(如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它.)此线程池 ...

  8. Java5中的线程池实例讲解

    Java5增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活.本文通过一个网络服务器模型,来实践Java5的多线程 ...

  9. 003-多线程-JUC线程池-几种特殊的ThreadPoolExecutor【newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool】

    一.概述 在java doc中,并不提倡我们直接使用ThreadPoolExecutor,而是使用Executors类中提供的几个静态方法来创建线程池: 以下方法是Executors下的静态方法,Ex ...

随机推荐

  1. Android目录结构

    |ABI-- 应用程序二进制接口(application binary interface,ABI) |-- Makefile |-- bionic               (bionic C库) ...

  2. SQLServer数据库查看死锁、堵塞情况

    在压力测试过程中,不间断的按F5键执行上面的SQL语句,如果出现死锁或者堵塞现象,就会在执行结果中罗列出来.如果每次连续执行SQL,都有死锁或者堵塞出现,说明死锁或者堵塞的比较严重. --每秒死锁数量 ...

  3. 【机房收费系统 4】:VB获取标准北京时间,免除时间误差

    导读:这又是师傅给我指出的一个问题,说实话,其实开始根本没有当回事,觉得麻烦,可是,等我完成了获取标准北京时间后,我发现,这一步,是必须的.谢谢师傅对我的严格要求,让我一步一步的成长起来! 一.事件缘 ...

  4. Cookie窃取实验

    文章:IE/FIREFOX/CHROME等浏览器保存COOKIE的位置 Chrome的Cookie数据位于:%LOCALAPPDATA%\Google\Chrome\User Data\Default ...

  5. next_permutation

    实验了一下next_permutation 代码如下 #include <cstdio> #include <cstdlib> #include <cstring> ...

  6. 【Luogu】P1681最大正方形2(异或运算,DP)

    题目链接 不得不说attack是个天才.读入使用异或运算,令que[i][j]^=(i^j)&1,于是原题目变成了求que数组的最大相同值. 然而我还是不理解为啥,而且就算简化成这样我也不会做 ...

  7. 【bzoj1193】[HNOI2006]马步距离

    [HNOI2006]马步距离 Description Input 只包含4个整数,它们彼此用空格隔开,分别为xp,yp,xs,ys.并且它们的都小于10000000. Output 含一个整数,表示从 ...

  8. cf493E Vasya and Polynomial

    Vasya is studying in the last class of school and soon he will take exams. He decided to study polyn ...

  9. Oracle Partition 分区详细总结

    此文从以下几个方面来整理关于分区表的概念及操作:        1.表空间及分区表的概念        2.表分区的具体作用        3.表分区的优缺点        4.表分区的几种类型及操作 ...

  10. HDU 5001 Walk (暴力、概率dp)

    Walk Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Sub ...