zoukankan      html  css  js  c++  java
  • Java 多线程编程之九:使用 Executors 和 ThreadPoolExecutor 实现的 Java 线程池的例子

            线程池用来管理工作线程的数量,它持有一个等待被执行的线程的队列。
            java.util.concurrent.Executors 提供了 java.util.concurrent.Executor 接口实现来创建 Java 里的线程池。我们写一个简单的程序来解释一下它的工作机制。
            首先我们需要有一个 Runnable 类。
            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;
        }
    }


            这里是我们使用 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(); // This will make the executor accept no new threads and finish all existing threads in the queue
            while (!executor.isTerminated()) { // Wait until all threads are finish,and also you can use "executor.awaitTermination();" to wait
            }
            System.out.println("Finished all threads");
        }
     
    }


            程序中我们创建了固定大小为五个工作线程的线程池。然后分配给线程池十个工作,因为线程池大小为五,它将启动五个工作线程先处理五个工作,其他的工作则处于等待状态,一旦有工作完成,空闲下来工作线程就会捡取等待队列里的其他工作进行执行。
            这里是以上程序的输出。
    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 类提供了使用了 ThreadPoolExecutor 的简单的 ExecutorService 实现,但是 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 提供了一些方法,我们可以使用这些方法来查询 executor 的当前状态,线程池大小,活动线程数量以及任务数量。因此我是用来一个监控线程在特定的时间间隔内打印 executor 信息。
            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。因此如果已经有四个正在执行的任务而此时分配来更多任务的话,工作队列将仅仅保留他们(新任务)中的两个,其他的将会被 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

            注意 executor 的活动任务、完成任务以及所有完成任务,这些数量上的变化。我们可以调用 shutdown() 方法来结束所有提交的任务并终止线程池。
    原文链接: http://www.journaldev.com/1069/java-thread-pool-example-using-executors-and-threadpoolexecutor

  • 相关阅读:
    网曝!互联网公司那些老司机才懂的秘密~~
    中国IT行业薪资:与销售相比,程序员真得很“穷”
    太简单了,教你去掉Java代码中烦人的“!=null”
    怎么判断自己在不在一家好公司?
    内部泄露版!互联网大厂的薪资和职级一览
    重磅!GitHub突然宣布,对全球人免费开放全部核心功能
    痛心!Pandownload开发者被抓!我终于决定使用Docker搭建一个多端同步网盘!
    退税:我承认我有赌的成分
    golang实现的简单优先队列
    ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (13)解答
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3233642.html
Copyright © 2011-2022 走看看