Java并发37:Executor系列--Executor接口学习笔记
1.Executor接口概述
@since 1.5
Executor,又称为执行器,它可以执行已经提交的Runnable接口类型的任务。
这个接口提供了一种将任务提交从任务运行(包括在线程使用、调度等待)分离出来的方法。
Executor接口通常用来显式地创建线程。
例如,相较于为每一组任务调用new Thread(new(RunnableTask())).start(),你也可以使用下面的方式:
Executor executor = new Executor(); executor.execute(new RunnableTask1()); executor.execute(new RunnableTask2()); ...
然而,Executor接口并不是严格的要求运行是异步的。
在最简单的情况下,executor可以在调用者的线程中立即运行提交的任务:
class DirectExecutor implements Executor { public void execute(Runnable r) { r.run(); } }
更典型的是,任务运行在其他线程中,而非调用者的线程中。
下面的执行器为每一个任务开启一个新线程:
class ThreadPerTaskExecutor implements Executor { public void execute(Runnable r) { new Thread(r).start(); } }
很多Executor接口的实现类对如何以及何时调度任务施加了一些限制。
下面的执行器将任务提交给第二个执行器,构建了一个组合型的执行器。
class SerialExecutor implements Executor { final Queue<Runnable> tasks = new ArrayDeque<Runnable>(); final Executor executor; Runnable active; SerialExecutor(Executor executor) { this.executor = executor; } public synchronized void execute(final Runnable r) { tasks.offer(new Runnable() { public void run() { try { r.run(); } finally { scheduleNext(); } } }); if (active == null) { scheduleNext(); } } protected synchronized void scheduleNext() { if ((active = tasks.poll()) != null) { executor.execute(active); } } }
ExecutorService接口是Executor接口的一种实现,是一种更加广泛的接口。
ThreadPoolExecutor类提供了一个可扩展的线程池的实现。
Executors工具类为执行器提供了方便的工厂方法。
谨记一致性影响
一个线程中,提交一个Runnable类型的任务到执行器之前的操作 happens-before 另一个线程中,它运行之后的操作。
即:
一个线程中,提交一个Runnable类型的任务到执行器之前的操作 对 另一个线程中,它运行之后的操作 可见。
关于void execute(Runnable command)方法
作用:在将来的某个时刻,执行给定的命令。
基于执行器的实现方式的不同,命令执行的线程也会不同。
命令可能执行在一个新线程中、一个线程池管理的线程中或者一个调用者本身的线程中。
2.Executor的作用
Executor的主要作用:提供了一种显示创建线程的方式。
JDK1.5之前的方式:Thread + Runnable
Executor提供的的方式:Executor + Runnable
3.实例练习
练习目的:理解两种创建线程的方式。
练习内容:
定义两个Runnable接口对象。
分别用Thread和Executor方式创建线程。
实例代码:
//定义第1个Runnable接口对象Runnable runnable1 = new Runnable() { @Override
public void run() { System.out.println(Thread.currentThread().getName() + " is first Runnable Object."); } }; //定义第2个Runnable接口对象 Runnable runnable2 = new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is second Runnable Object."); } }; System.out.println("======通过Thread运行:原始方式"); //方式1:通过Thread运行 Thread thread1 = new Thread(runnable1); thread1.start(); Thread thread2 = new Thread(runnable2); thread2.start(); Thread.sleep(100); System.out.println(); System.out.println("======通过Executor运行:便于统一调度"); //方式2:通过Executor运行 //Executor通常通过Executors工具类的静态方法实例化对象
//这个地方用Executors创建线程不太好。请参考手动创建线程池,效果会更好哦。 Executor executor = Executors.newCachedThreadPool(); //Executor只有一个方法execute(),用于执行Runnable接口 executor.execute(runnable1); executor.execute(runnable2);
运行结果:
======通过Thread运行:原始方式 Thread-1 is second Runnable Object. Thread-0 is first Runnable Object. ======通过Executor运行:便于统一调度 pool-1-thread-1 is first Runnable Object. pool-1-thread-2 is second Runnable Object.