并发编程之Executors及其子类

     java.util.concurrent.Executors是个工具类,它提供对Executor、ExecutorService、ScheduledExecutorService、ThreadFactory、Callable、ExecutorCompletionService、Future等类的一些实用方法。其中Callable、Future和FutureTask在《并发编程之Callable和Future接口、FutureTask类》一文中已经进行过描述。并发编程的一种编程方式是把任务拆分为一些列的小任务,即Runnable,然后在提交给一个Executor执行,Executor.execute(Runnalbe) 。Executor在执行时使用内部的线程池完成操作。
一、创建线程池
Executors类提供了一系列工厂方法用于创建线程池,返回的线程池都实现了ExecutorService接口。
1、public static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory)
     创建一个可重用的固定线程数的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的
ThreadFactory 创建新线程(该参数是可选的)。在任意点,在大多数nThreads线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果线程在关闭前执行某个任务期间由于失败而导致任何线程终止,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。
2、public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory)
     创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用execute将重用以前构造的线程(如果线程可用),并在需要时使用提供的 ThreadFactory创建新线程。如果没有可用的线程,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。注意,可以使用ThreadPoolExecutor构造方法创建具有类似属性但细节不同(例如超时参数)的线程池。
3、public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
      创建一个使用单个worker线程的 Executor,以无界队列方式来运行该线程,并在需要时使用提供的ThreadFactory创建新线程。与其他等效的newFixedThreadPool(1, threadFactory) 不同,可保证不能对ThreadPoolExecutor重新进行配置来使用更多的线程。注意:newSingleThreadExecutor返回的ExcutorService在析构函数finalize()会调用shutdown(),即如果我们没有对它调用shutdown(),那么可以确保它在被回收时调用shutdown()来终止线程。
4、public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory
threadFactory)
      创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。(注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,一个新线程会代替它执行后续的任务)。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的newScheduledThreadPool(1, threadFactory) 不同,可保证不能对ScheduledThreadPoolExecutor重新进行配置来使用更多的线程。
5、public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
       创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。多数情况下可用来替代Timer类。
6、public static ExecutorService unconfigurableExecutorService(ExecutorService executor)
      返回一个将所有已定义的 ExecutorService 方法委托给指定执行程序的对象,这样就无法使用强制转换来访问其他的方法。这提供了一种可安全地“冻结”配置并且不允许调整给定具体实现的方法。注意:它的目的是只暴露ExecutorService接口方法,使特定于实现的方法不可访问,它是通过一个类来包装executor来实现的,该类实现了ExecutorService接口。具体来说只是调用executor的相应函数。
7、public static ScheduledExecutorService unconfigurableScheduledExecutorService
(ScheduledExecutorService executor)
      返回一个将所有已定义的 ExecutorService 方法委托给指定执行程序的对象,这样就无法使用强制转换来访问其他的方法,这提供了一种可安全地“冻结”配置并且不允许调整给定具体实现的方法。注意:其目的和unconfigurableExecutorService相似。
8、public static ThreadFactory defaultThreadFactory()
      返回用于创建新线程的默认线程工厂。此工厂创建同一ThreadGroup中Executor使用的所有新线程。如果有SecurityManager,则它使用 System.getSecurityManager()组来调用此defaultThreadFactory方法,其他情况则使用线程组。每个新线程都作为非守护程序而创建,并且具有设置为Thread.NORM_PRIORITY中较小者的优先级以及线程组中允许的最大优先级。新线程具有可通过pool-N-thread-M的Thread.getName()来访问的名称,其中N是此工厂的序列号,M是此工厂所创建线程的序列号。
9、public static ThreadFactory privilegedThreadFactory()
     返回用于创建新线程的线程工厂,这些新线程与当前线程具有相同的权限。此工厂创建具有与defaultThreadFactory() 相同设置的线程,新线程的 AccessControlContext 和 contextClassLoader 的其他设置。与调用此 privilegedThreadFactory方法的线程相同。可以在AccessController.doPrivileged(java.security.PrivilegedAction) 操作中创建一个新 privilegedThreadFactory,设置当前线程的访问控制上下文,以便创建具有该操作中保持的所选权限的线程。

    注意,虽然运行在此类线程中的任务具有与当前线程相同的访问控制和类加载器,但是它们无需具有相同的ThreadLocal或 InheritableThreadLocal值。如有必要,使用ThreadPoolExecutor.beforeExecute (java.lang.Thread, java.lang.Runnable),在ThreadPoolExecutor子类中运行任何任务前,可以设置或重置线程局部变量的特定值。另外,如果必须初始化 worker 线程,以具有与某些其他指定线程相同的InheritableThreadLocal设置,则可以在线程等待和服务创建请求的环境中创建自定义的 ThreadFactory,而不是继承其值。
10、ScheduledExecatorService类提供了schedule方法执行简单的延迟任务外还提供了scheduleAtFixedRate(command, initialDelay, period, unit)方法,该方法可以指定任务按照一定的频率执行(前后两次任务执行的时间间隔相同);scheduleWithFixedDelay(command, initialDelay, delay, unit)方法在给定延迟时间之后第一次执行任务,之后任务按照固定的时间间隔执行(本次任务执行完毕到下一次任务开始),这类调度可以用于新闻聚合应用。

二、ExecutorService与生命周期
       ExecutorService扩展了Executor并添加了一些生命周期管理的方法。一个Executor的生命周期有三种状态:运行、关闭、终止。Executor创建时处于运行状态。当调用ExecutorService.shutdown()后,处于关闭状态,isShutdown()方法返回true。这时,不应该再想Executor中添加任务,所有已添加的任务执行完毕后,Executor处于终止状态,isTerminated()返回true。如果Executor处于关闭状态,往Executor提交任务会抛出unchecked exception RejectedExecutionException。
     ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。如果Executor后台线程池还没有完成Callable的计算,这调用返回Future对象的get()方法,会阻塞直到计算完成。

演示调度任务执行:

import java.awt.Dimension;
import java.awt.Toolkit;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class VirusScanner {
	private static JFrame appFrame;
	private static JLabel stattusString;
	private int scanNumber = 0;
	private static VirusScanner app = new VirusScanner();

	private static final ScheduledExecutorService scheduler = Executors
			.newScheduledThreadPool(5);

	public void scanDisk() {
		final Runnable scanner = new Runnable() {
			@Override
			public void run() {
				appFrame.setVisible(true);
				scanNumber++;
				Calendar cal = Calendar.getInstance();
				DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL,
						DateFormat.MEDIUM);
				stattusString.setText(" Scan " + scanNumber + " started at "
						+ df.format(cal.getTime()));
				System.out.println(Thread.currentThread().getName());
				try {
					Thread.sleep(10000 + new Random().nextInt(1000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				appFrame.setVisible(false);
			}
		};

		final ScheduledFuture<?> scanManager = scheduler.scheduleAtFixedRate(
				scanner, 1, 2, TimeUnit.SECONDS);
		//
		scheduler.schedule(new Runnable() {
			@Override
			public void run() {
				scanManager.cancel(true);
				scheduler.shutdown();
				appFrame.setEnabled(false);
			}
		}, 60, TimeUnit.SECONDS);
	}

	public static void main(String[] args) {
		appFrame = new JFrame();
		Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
		appFrame.setSize(400, 70);
		appFrame.setLocation(dimension.width / 2 - appFrame.getWidth() / 2,
				dimension.height / 2 - appFrame.getHeight() / 2);
		stattusString = new JLabel();
		appFrame.add(stattusString);
		appFrame.setVisible(true);
		app.scanDisk();
	}
}
三、CompletionService
      在某些情况下,当提交多个任务给执行器时,你可能需要处理任意已经结束的结果,而不想等到每个任务都执行结束。为了解决这个问题可以使用CompletionService。生产者submit()执行的任务。使用者take()已完成的任务,并按照完成这些任务的顺序处理它们的结果 。也就是调用CompletionService的take方法是,会返回按完成顺序放回任务的结果,CompletionService内部维护了一个阻塞队列BlockingQueue,如果没有任务完成,take()方法也会阻塞。示例程序如下:
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MultipleServices {

	public static class Exp implements Callable<Double> {
		private double m;
		private int n;

		public Exp(double m, int n) {
			this.m = m;
			this.n = n;
		}

		@Override
		public Double call() throws Exception {
			double result = 1;
			for (int i = 0; i < n; i++) {
				result *= m;
				Thread.sleep(10);
			}
			System.out.printf("%nComputed %.02f raised to %d%n", m, n);
			return result;
		}
	}

	public static void main(String[] args) {
		ExecutorService executor = Executors.newFixedThreadPool(10);
		ArrayList<Callable<Double>> tasks = new ArrayList<Callable<Double>>();
		for (int i = 0; i < 10; i++) {
			double m = Math.random() * 10;
			int n = (int) (Math.random() * 1000);
			System.out.printf("Created task for computing: "
					+ "%.02f raised to %d\n", m, n);
			tasks.add(new Exp(m, n));
		}
		ExecutorCompletionService<Double> service = new ExecutorCompletionService<Double>(
				executor);
		for (Callable<Double> task : tasks) {
			service.submit(task);
		}
		Lock lock = new ReentrantLock();
		for (int i = 0; i < tasks.size(); i++) {
			lock.lock();
			try {
				Double d = (Double) service.take().get();
				System.out.printf("Result: %E%n", d);
				lock.unlock();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
		}
		executor.shutdown();
	}
}
执行结果:

Created task for computing: 0.01 raised to 116
Created task for computing: 7.75 raised to 771
Created task for computing: 3.47 raised to 526
Created task for computing: 1.90 raised to 172
Created task for computing: 1.59 raised to 983
Created task for computing: 9.02 raised to 869
Created task for computing: 2.70 raised to 496
Created task for computing: 5.24 raised to 347
Created task for computing: 7.04 raised to 464
Created task for computing: 0.81 raised to 90

Computed 0.81 raised to 90
Result: 8.390124E-09

Computed 0.01 raised to 116
Result: 1.859655E-214

Computed 1.90 raised to 172
Result: 1.123777E+48

Computed 5.24 raised to 347
Result: 4.201412E+249

Computed 7.04 raised to 464
Result: INFINITY

Computed 2.70 raised to 496
Result: 1.380109E+214

Computed 3.47 raised to 526
Result: 1.583105E+284

Computed 7.75 raised to 771
Result: INFINITY

Computed 9.02 raised to 869
Result: INFINITY

Computed 1.59 raised to 983
Result: 7.652763E+198

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值