深度理解Thread Pool, Executor, Callable/Future

在JDK1.5版,Java标准包中就包含了对线程池的支持,提供了包java.lang.concurrent.

1. ThreadPool

线程池是一个线程管理的集合,能够有效执行任务。当大量任务使用线程池执行时,由于线程循环的执行,整个性能得到提高,也减少了每个任务调用上的花费。实现线程池,你能够运用ExecutorService的实现类,比如ThreadPoolExecutor或是ScheduledThreadPoolExecutor。另外,在类Executors中提供了如下更方便的工厂方法:

  • Executors.newSingleThreadExecutor(): 创建一个单一后台线程实例.
  • Executors.newFixedThreadPool(int numThreads): 创建一个可以修复线程池大小实例.
  • Executors.newCachedThreadPool():运用自动化线程回收利用来创建一个非绑定线程池实例。

使用线程池的步骤如下:

  1. 编写出实现了Runnable接口的工人线程类,run()方法指定了运行线程的行为。
  2. 使用由Executor类提供的工厂方法创建一个线程池(ExecutorService),这个线程池可以是Executors.newSingleThreadExecutor(),或者Executors.newFixedThreadPool(int numThreads),也可以是Executors.newCachedThreadPool()创建的。
  3. 创建你的工人线程实例,使用execute(Runnable)方法去添加一个Runnable任务到线程池中。如何在池中有一个有效的线程,这个任务将会被调度并执行。
2. 理解相关API

一个Executor对象能够执行Runnable提交的任务。Executor接口类(1.6version)中的方法:

    void execute(Runnable command);

它在不久的某个时间里执行一个给予任务。

接口ExecutorService定义了一些有用的方法,重要的两个如下:

public void shutdown();
   // Initiates an orderly shutdown of the thread pool.
   // The previously executed/submitted tasks are allowed to complete,
   // but no new tasks will be scheduled.
public <T> Future<T> submit(Callable<T> task);
   // Submit or schedule the callable task for execution, which returns a Future object.

Executors类中定义一些有用的方法:

static ExecutorService newSingleThreadExecutor()
static ExecutorService newFixedThreadPool(int nThreads)
static ExecutorService newCachedThreadPool()
static ScheduledExecutorService newSingleThreadScheduledExecutor()
static ScheduledExecutorService newScheduledThreadPool(int size)

一个简单的例子来说明一下如何调用使用线程池。

public class WorkerThread implements Runnable {
   private int workerNumber;

   WorkerThread(int workerNumber) {
      this.workerNumber = workerNumber;
   }

   public void run() {
      // The thread simply prints 1 to 5
      for (int i = 1; i <= 5; i++) {
         System.out.printf("Worker %d: %d\n", workerNumber, i);
         try {
            // sleep for 0 to 0.5 second
            Thread.sleep((int)(Math.random() * 500));
         } catch (InterruptedException e) {}
      }
   }
}

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolTest {
   public static void main(String[] args) {
      int numWorkers = Integer.parseInt(args[0]);
      int threadPoolSize = Integer.parseInt(args[1]);

      ExecutorService pool = 
            Executors.newFixedThreadPool(threadPoolSize);
      WorkerThread[] workers = new WorkerThread[numWorkers];
      for (int i = 0; i < numWorkers; i++) {
         workers[i] = new WorkerThread(i+1);
         pool.execute(workers[i]);
      }
      pool.shutdown();
   }
}
结果如下:
Worker 1: 1
Worker 2: 1
Worker 2: 2
Worker 2: 3
Worker 2: 4
Worker 1: 2
Worker 1: 3
Worker 2: 5
Worker 1: 4
Worker 1: 5
Worker 3: 1
Worker 3: 2
Worker 4: 1
Worker 3: 3
Worker 3: 4
Worker 4: 2
Worker 3: 5
Worker 4: 3
Worker 5: 1
Worker 4: 4
Worker 5: 2
Worker 5: 3
Worker 4: 5
Worker 5: 4
Worker 5: 5

接口Callable和Runnable。 Callable与Runnable很相似。然而, Callable提供了一种能够固定在线程上的返回结果或是出现的异常。

public V call()
   // Call() returns a result of type <V>, or throws an exception if unable to do so.

在线程池中,使用submit(Callable r)可以返回一个Future<V>(在ExecutorService接口类中声明)对象。当需要有返回结果时,可以检索get()方法来获得。如果不出现异常,会返回准备的结果。

Future<V>的方法如下:

V get()           // wait if necessary, retrieve result
V get(long timeout, TimeUnit unit)
boolean cancel(boolean mayInterruptIfRunning)
boolean isCancelled()
boolean isDone()  // return true if this task completed

同样的例子,换一种写法:

public class CallableWorkerThread implements Callable<String> {

    private int workerNumber;

    CallableWorkerThread(int workerNumber) {
        this.workerNumber = workerNumber;
    }

    public String call() {    // use call() instead of run()
        for (int i = 1; i <= 5; i++) {    // just print 1 to 5
            System.out.printf("Worker %d: %d\n", workerNumber, i);
            try {
                Thread.sleep((int)(Math.random() * 1000));
            } catch (InterruptedException e) {}
        }
        return "worker " + workerNumber;
    }
}

package org.concurrency.simple;

/**
 * @author: John Liu
 */
import java.util.concurrent.*;

public class CallableThreadPoolTest {
    public static void main(String[] args) {
        int numWorkers = 5;

        ExecutorService pool = Executors.newCachedThreadPool();
        CallableWorkerThread workers[] = new CallableWorkerThread[numWorkers];
        Future[] futures = new Future[numWorkers];

        for (int i = 0; i < numWorkers; i++) {
            workers[i] = new CallableWorkerThread(i + 1);
            futures[i] = pool.submit(workers[i]);
        }
        for (int i = 0; i < numWorkers; i++) {
            try {
                System.out.println(futures[i].get() + " ended");
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            } catch (ExecutionException ex) {
                ex.printStackTrace();
            }
        }
    }
}

结果:

Worker 2: 1
Worker 4: 1
Worker 5: 1
Worker 1: 1
Worker 3: 1
Worker 4: 2
Worker 4: 3
Worker 2: 2
Worker 4: 4
Worker 5: 2
Worker 1: 2
Worker 3: 2
Worker 4: 5
Worker 5: 3
Worker 2: 3
Worker 5: 4
Worker 3: 3
Worker 1: 3
Worker 2: 4
Worker 1: 4
Worker 3: 4
Worker 5: 5
Worker 2: 5
Worker 1: 5
Worker 3: 5
worker 1 ended
worker 2 ended
worker 3 ended
worker 4 ended
worker 5 ended


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值