多线程 Future Executor 接口体系【API】

Future<V>

public interface Future<V>
1
1
 
1
public interface Future<V>
类型参数:V - 此 Future 的 get 方法所返回的结果类型

所有已知子接口: Response<T>, RunnableFuture<V>, ScheduledFuture<V>, RunnableScheduledFuture<V>
所有已知实现类: FutureTask, SwingWorker

Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。计算完成后只能使用 get 方法来获取结果,如有必要,计算完成前可以阻塞此方法。取消则由 cancel 方法来执行。 还提供了其他方法,以确定任务是正常完成还是被取消了。一旦计算完成,就不能再取消计算。如果为了可取消性而使用 Future 但又不提供可用的结果,则可以声明 Future<?> 形式类型、并返回 null 作为底层任务的结果。

方法:
  • boolean  cancel(boolean mayInterruptIfRunning)   试图取消对此任务的执行。
    • 如果任务已完成、或已取消,或者由于某些其他原因而无法取消,则此尝试将失败。
    • 当调用 cancel 时,如果调用成功,而此任务尚未启动,则此任务将永不运行。
    • 参数:mayInterruptIfRunning - 如果任务已经启动,此参数用于确定是否应该以试图停止任务的方式来中断执行此任务的线程。
      • 如果应该中断执行此任务的线程,则为 true;否则允许正在运行的任务运行完成。
    • 返回:如果无法取消任务,则返回 false,这通常是由于它已经正常完成;否则返回 true
      • 此方法返回后,对 isDone() 的后续调用将始终返回 true。
      • 如果此方法返回 true,则对 isCancelled() 的后续调用将始终返回 true。
  • V  get()   如有必要,等待计算完成,然后获取其结果。
    • 抛出:
      • CancellationException - 如果计算被取消
      • ExecutionException - 如果计算抛出异常
      • InterruptedException - 如果当前的线程在等待时被中断
  • V  get(long timeout, TimeUnit unit)  如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)
    • 抛出:TimeoutException - 如果等待超时
    • 参数:
      • timeout - 等待的最大时间
      • unit - timeout 参数的时间单位
  • boolean  isCancelled()  如果在任务正常完成前将其取消,则返回 true。
  • boolean  isDone()  如果任务已完成,则返回 true。可能由于正常终止、异常或取消而完成,在所有这些情况中,此方法都将返回 true。

RunnableFuture<V>

public interface RunnableFuture<V> extends Runnable, Future<V>
1
1
 
1
public interface RunnableFuture<V> extends Runnable, Future<V>
类型参数:V - 此 Future 的 get 方法所返回的结果类型。

所有超级接口: Future<V>, Runnable
所有已知子接口: RunnableScheduledFuture<V>
所有已知实现类: FutureTask, SwingWorker

作为 Runnable 的 Future。成功执行 run 方法可以完成 Future 并允许访问其结果。
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。
使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。
2
 
1
Runnable 接口应该由那些打算通过某一线程执行其实例的类来实现。设计该接口的目的是为希望在活动时执行代码的对象提供一个公共协议。
2
使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。
void  run()   【此方法其实就是 Runnable 接口中定义的方法】在未被取消的情况下,将此 Future 设置为计算的结果。

ScheduledFuture<V>

public interface ScheduledFuture<V>  extends  Delayed,  Future<V>
1
1
 
1
public interface ScheduledFuture<V>  extends  Delayed,  Future<V>
类型参数:V - 此 Future 的 get 方法所返回的结果类型。

所有超级接口: Comparable< Delayed>, Delayed, Future<V>
所有已知子接口: RunnableScheduledFuture<V>

一个延迟的、结果可接受的操作,可将其取消。通常已安排的 future 是用 ScheduledExecutorService 安排任务的结果。

此接口中 没有定义方法

RunnableScheduledFuture<V>

public interface RunnableScheduledFuture<V>  extends  RunnableFuture<V>,  ScheduledFuture<V>
1
1
 
1
public interface RunnableScheduledFuture<V>  extends  RunnableFuture<V>,  ScheduledFuture<V>
类型参数: V - 此 Future 的 get 方法所返回的结果类型。

所有超级接口: Comparable< Delayed>, Delayed, Future<V>, Runnable, RunnableFuture<V>, ScheduledFuture<V>

作为 Runnable 的 ScheduledFuture。成功执行 run 方法可以完成 Future 并允许访问其结果。

boolean isPeriodic() :   如果这是一个定期任务,则返回 true。定期任务可以根据计划重新运行。非定期任务只能运行一次。

Executor

public interface Executor
1
1
 
1
public interface Executor
所有已知子接口: ExecutorService, ScheduledExecutorService
所有已知实现类: AbstractExecutorService, ScheduledThreadPoolExecutor, ThreadPoolExecutor

执行已提交的 Runnable 任务的对象。
此接口提供一种 将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法
通常使用 Executor 而不是显式地创建线程。例如,可能会使用以下方法:
 executor.execute(new RunnableImp()); //执行已提交的 Runnable 任务的对象
1
 
1
 executor.execute(new RunnableImp()); //执行已提交的 Runnable 任务的对象
而不是为一组任务中的每个任务调用:
new Thread(new(RunnableImp())).start();
1
 
1
new Thread(new(RunnableImp())).start();

不过, Executor 接口并没有严格地要求执行是异步的(PS:之所以这么说,是因为Thread的执行一定是异步的)。在最简单的情况下,执行程序可以在调用者的线程中立即运行已提交的任务:
class DirectExecutor implements Executor {
    @Override
    public void execute(Runnable r) {
        r.run(); //在调用者的线程中立即运行已提交的任务,而不是new一个Thread在一个新线程中执行,也即任务执行在调用者所在的线程
    }
}
6
 
1
class DirectExecutor implements Executor {
2
    @Override
3
    public void execute(Runnable r) {
4
        r.run(); //在调用者的线程中立即运行已提交的任务,而不是new一个Thread在一个新线程中执行,也即任务执行在调用者所在的线程
5
    }
6
}

更常见的是,任务是在某个不是调用者线程的线程中执行的。以下执行程序将为每个任务生成一个新线程:
class ThreadPerTaskExecutor implements Executor {
    @Override
    public void execute(Runnable r) {
        new Thread(r).start();//为每个任务生成一个新线程,这其实就是在一个新线程中异步执行任务
    }
}
6
 
1
class ThreadPerTaskExecutor implements Executor {
2
    @Override
3
    public void execute(Runnable r) {
4
        new Thread(r).start();//为每个任务生成一个新线程,这其实就是在一个新线程中异步执行任务
5
    }
6
}

许多 Executor 实现都对调度任务的 方式和时间强加了某种限制。
此包中提供的 Executor 实现实现了 ExecutorService,这是一个使用更广泛的接口。
PS:这句话的意思是这样的
1、此包指的是并发包 java.util.concurrent
2、此包中Executor的所有已知实现类有这些:AbstractExecutorService, ScheduledThreadPoolExecutor, ThreadPoolExecutor
3、此包中Executor的所有已知实现类都实现了ExecutorService接口
4、其实ExecutorService接口是Executor接口的子接口
5
 
1
PS:这句话的意思是这样的
2
1、此包指的是并发包 java.util.concurrent
3
2、此包中Executor的所有已知实现类有这些:AbstractExecutorService, ScheduledThreadPoolExecutor, ThreadPoolExecutor
4
3、此包中Executor的所有已知实现类都实现了ExecutorService接口
5
4、其实ExecutorService接口是Executor接口的子接口
ThreadPoolExecutor 类提供一个可扩展的线程池实现。
Executors 类为这些 Executor 提供了便捷的工厂方法。

void execute(Runnable command)    在未来某个时间执行给定的命令。该命令可能在新的线程、已入池的线程或者正调用的线程中执行,这由 Executor 实现决定。
  • 参数:command - 可运行的任务
  • 抛出:
    • RejectedExecutionException - 如果不能接受执行此任务。
    • NullPointerException - 如果命令为 null

ExecutorService【核心接口】

public interface ExecutorService extends Executor
1
1
 
1
public interface ExecutorService extends Executor
所有超级接口: Executor
所有已知子接口: ScheduledExecutorService
所有已知实现类: AbstractExecutorService, ScheduledThreadPoolExecutor, ThreadPoolExecutor

ExecutorService是Executor直接的扩展接口,也是 最常用的线程池接口,我们通常见到的线程池定时任务线程池都是它的实现类。
Executor的实现提供的一些方法可以返回一个 Future , 通过它我们可以跟踪到异步任务的执行和停止。

ExecutorService 可以被关闭来拒绝新任务。有两个不同的方法来关闭 ExecutorServiceshutdown 方法在关闭 ExecutorService 之前等待提交的任务执行完成, shutdownNow 方法会阻止开启新的任务并且尝试停止当前正在执行的线程,一旦调用该方法,线程池中将没有激活的任务,没有等待执行的任务,并且无法提交新任务。 应该关闭未使用的 ExecutorService 以允许回收其资源。

方法 submit 扩展了 Executor.execute(Runnable) 方法, 创建并返回一个 Future 结果,这个Future可以取消任务的执行或者等待完成得到返回值。
方法 invokeAny 和 invokeAll 可以执行一组任务,等待至少一个任务 或全部任务完成(可使用 ExecutorCompletionService 类来编写这些方法的自定义变体)。
Executors 类提供了用于此包中所提供的执行程序服务的工厂方法。

用法示例
下面给出了一个网络服务的简单结构,这里线程池中的线程作为传入的请求。它使用了预先配置的 Executors.newFixedThreadPool(int) 工厂方法:
class NetworkService implements Runnable {
	private ServerSocket serverSocket;
	private ExecutorService pool;

	public NetworkService(int port, int poolSize) throws IOException {
		serverSocket = new ServerSocket(port);
		pool = Executors.newFixedThreadPool(poolSize);
	}

	@Override
	public void run() {
		System.out.println("run the service");
		try {
			for (;;) {
				System.out.println("start execute...");
				pool.execute(new MyRunnable(serverSocket.accept()));
				System.out.println("end execute...");
			}
		} catch (IOException ex) {
			pool.shutdown();
		}
	}
}

class MyRunnable implements Runnable {
	private final Socket socket;

	MyRunnable(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		System.out.println("read and service request on socket");
	}
}
36
 
1
class NetworkService implements Runnable {
2
    private ServerSocket serverSocket;
3
    private ExecutorService pool;
4
5
    public NetworkService(int port, int poolSize) throws IOException {
6
        serverSocket = new ServerSocket(port);
7
        pool = Executors.newFixedThreadPool(poolSize);
8
    }
9
10
    @Override
11
    public void run() {
12
        System.out.println("run the service");
13
        try {
14
            for (;;) {
15
                System.out.println("start execute...");
16
                pool.execute(new MyRunnable(serverSocket.accept()));
17
                System.out.println("end execute...");
18
            }
19
        } catch (IOException ex) {
20
            pool.shutdown();
21
        }
22
    }
23
}
24
25
class MyRunnable implements Runnable {
26
    private final Socket socket;
27
28
    MyRunnable(Socket socket) {
29
        this.socket = socket;
30
    }
31
32
    @Override
33
    public void run() {
34
        System.out.println("read and service request on socket");
35
    }
36
}

下列方法分两个阶段关闭 ExecutorService。第一阶段调用 shutdown 拒绝传入任务,然后调用 shutdownNow(如有必要)取消所有遗留的任务:
private void shutdownAndAwaitTermination(ExecutorService pool) {
	pool.shutdown(); // Disable new tasks from being submitted
	try {
		if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {// Wait a while for existing tasks to terminate
			pool.shutdownNow(); // Cancel currently executing tasks
			if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {// Wait a while for tasks to respond to being cancelled
				System.err.println("Pool did not terminate");
			}
		}
	} catch (InterruptedException ie) {
		pool.shutdownNow();// (Re-)Cancel if current thread also interrupted
		Thread.currentThread().interrupt();// Preserve interrupt status
	}
}
14
 
1
private void shutdownAndAwaitTermination(ExecutorService pool) {
2
    pool.shutdown(); // Disable new tasks from being submitted
3
    try {
4
        if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {// Wait a while for existing tasks to terminate
5
            pool.shutdownNow(); // Cancel currently executing tasks
6
            if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {// Wait a while for tasks to respond to being cancelled
7
                System.err.println("Pool did not terminate");
8
            }
9
        }
10
    } catch (InterruptedException ie) {
11
        pool.shutdownNow();// (Re-)Cancel if current thread also interrupted
12
        Thread.currentThread().interrupt();// Preserve interrupt status
13
    }
14
}

方法
关闭相关的方法
  • boolean  isShutdown()  如果此执行程序已关闭,则返回 true。
  • boolean  isTerminated()  如果关闭后所有任务都已完成,则返回 true。
    • 除非首先调用 shutdown 或 shutdownNow,否则 isTerminated 永不为 true。
  • void  shutdown()  启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
  • List<Runnable>  shutdownNow()  试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
    • 无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。
    • 它试图终止线程的方法是通过调用 Thread.interrupt() 方法来实现的,但是大家知道,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用,interrupt()方法是无法中断当前的线程的。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。
    • 返回:从未开始执行的任务的列表
  • boolean  awaitTermination(long timeout, TimeUnit unit)   阻塞,直到所有任务完成执行。
    • 当前线程阻塞,直到:等所有已提交的任务(包括正在跑的和队列中等待的)执行完,或者等超时时间到,或者线程被中断抛出InterruptedException,
    • 参数:timeout - 最长等待时间;unit - timeout 参数的时间单位
    • 返回:如果此执行程序终止(shutdown请求后所有任务执行完毕),则返回 true;如果终止前超时期满,则返回 false
    • 抛出:InterruptedException - 如果等待时发生中断


shutdown()、shutdownNow()、awaitTermination() 的区别:
  • shutdown(),将线程池状态置为SHUTDOWN,并不会立即停止:
    • 停止接收外部submit的任务
    • 内部正在跑的任务和队列里等待的任务,会执行完
    • 等到第二步完成后,才真正停止
  • shutdownNow(),将线程池状态置为STOP,企图立即停止,但并不一定:
    • 先停止接收外部提交的任务(跟shutdown一样)
    • 忽略队列里等待的任务
    • 尝试将正在跑的任务interrupt中断
    • 返回未执行的任务列表
  • awaitTermination(long timeOut, TimeUnit unit),当前线程阻塞,直到:
    • 等所有已提交的任务(包括正在跑的和队列中等待的)执行完
    • 或者等超时时间到
    • 或者线程被中断,抛出InterruptedException

其实,shuntdown()和awaitTermination()的效果差不多,方法执行之后,都要等到提交的任务全部执行完才停,其主要区别为:
  • shutdown()后,不能再提交新的任务进去但是awaitTermination()后,可以继续提交。
  • awaitTermination()是阻塞的,返回结果是线程池是否已停止;shutdown()不阻塞。

总结
  • 想立马关闭,并得到未执行任务列表,用shutdownNow()
  • 优雅的关闭,用shutdown()
  • 优雅的关闭,并允许关闭声明后新任务能提交,用awaitTermination()

一般情况配合使用 shutdown 和 awaitTermination 来关闭线程池。
public static void main(String[] args) {
	final Format format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault());
	ExecutorService pool = Executors.newFixedThreadPool(1);
	pool.execute(new Runnable() {
		@Override
		public void run() {
			boolean isLongTime = new Random().nextBoolean();
			System.out.println(format.format(new Date()) + "  start run................." + isLongTime);
			try {
				Thread.sleep(isLongTime ? 3 * 1000 : 1 * 1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(format.format(new Date()) + "  end run");
		}
	});

	//pool.shutdown();//当在 awaitTermination 方法中指定的延迟时间内所有任务执行完毕了,则 awaitTermination 返回true,否则返回false
    //pool.shutdownNow();//因为会立即尝试将正在跑的任务interrupt中断,所以 awaitTermination 一般都是返回false(除非有任务不能被中断)
    
	try {
		System.out.println(format.format(new Date()) + "  start block");
		boolean result = pool.awaitTermination(2, TimeUnit.SECONDS);//只有调用shutdown或shutdownNow关闭任务,
		System.out.println(format.format(new Date()) + "  end bloc........" + result);
		System.out.println("isShutdown=" + pool.isShutdown() + "____isTerminated=" + pool.isTerminated());
	} catch (InterruptedException e) {
		System.out.println(format.format(new Date()) + "  " + e.getMessage());
	}
}
29
 
1
public static void main(String[] args) {
2
    final Format format = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault());
3
    ExecutorService pool = Executors.newFixedThreadPool(1);
4
    pool.execute(new Runnable() {
5
        @Override
6
        public void run() {
7
            boolean isLongTime = new Random().nextBoolean();
8
            System.out.println(format.format(new Date()) + "  start run................." + isLongTime);
9
            try {
10
                Thread.sleep(isLongTime ? 3 * 1000 : 1 * 1000);
11
            } catch (InterruptedException e) {
12
                e.printStackTrace();
13
            }
14
            System.out.println(format.format(new Date()) + "  end run");
15
        }
16
    });
17
18
    //pool.shutdown();//当在 awaitTermination 方法中指定的延迟时间内所有任务执行完毕了,则 awaitTermination 返回true,否则返回false
19
    //pool.shutdownNow();//因为会立即尝试将正在跑的任务interrupt中断,所以 awaitTermination 一般都是返回false(除非有任务不能被中断)
20
    
21
    try {
22
        System.out.println(format.format(new Date()) + "  start block");
23
        boolean result = pool.awaitTermination(2, TimeUnit.SECONDS);//只有调用shutdown或shutdownNow关闭任务,
24
        System.out.println(format.format(new Date()) + "  end bloc........" + result);
25
        System.out.println("isShutdown=" + pool.isShutdown() + "____isTerminated=" + pool.isTerminated());
26
    } catch (InterruptedException e) {
27
        System.out.println(format.format(new Date()) + "  " + e.getMessage());
28
    }
29
}
当不执行 shutdown 或 shutdownNow 时:
2018.06.25 22:37:46 581  start block
2018.06.25 22:37:46 581  start run.................true
2018.06.25 22:37:48 584  end bloc........false
isShutdown=false____isTerminated=false
2018.06.25 22:37:49 583  end run

2018.06.25 22:38:14 050  start run.................false
2018.06.25 22:38:14 048  start block
2018.06.25 22:38:15 051  end run
2018.06.25 22:38:16 052  end bloc........false
isShutdown=false____isTerminated=false
11
 
1
2018.06.25 22:37:46 581  start block
2
2018.06.25 22:37:46 581  start run.................true
3
2018.06.25 22:37:48 584  end bloc........false
4
isShutdown=false____isTerminated=false
5
2018.06.25 22:37:49 583  end run
6
7
2018.06.25 22:38:14 050  start run.................false
8
2018.06.25 22:38:14 048  start block
9
2018.06.25 22:38:15 051  end run
10
2018.06.25 22:38:16 052  end bloc........false
11
isShutdown=false____isTerminated=false
当执行 shutdown 时:
2018.06.25 22:42:42 442  start run.................true
2018.06.25 22:42:42 442  start block
2018.06.25 22:42:44 453  end bloc........false
isShutdown=true____isTerminated=false
2018.06.25 22:42:45 464  end run

2018.06.25 22:39:21 105  start block
2018.06.25 22:39:21 105  start run.................false
2018.06.25 22:39:22 107  end run
2018.06.25 22:39:22 107  end bloc........true
isShutdown=true____isTerminated=true
11
 
1
2018.06.25 22:42:42 442  start run.................true
2
2018.06.25 22:42:42 442  start block
3
2018.06.25 22:42:44 453  end bloc........false
4
isShutdown=true____isTerminated=false
5
2018.06.25 22:42:45 464  end run
6
7
2018.06.25 22:39:21 105  start block
8
2018.06.25 22:39:21 105  start run.................false
9
2018.06.25 22:39:22 107  end run
10
2018.06.25 22:39:22 107  end bloc........true
11
isShutdown=true____isTerminated=true
当执行 shutdownNow 时:
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at Test$1.run(Test.java:20)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
2018.06.25 22:44:05 987  start block
2018.06.25 22:44:05 987  start run.................false
2018.06.25 22:44:05 989  end run
2018.06.25 22:44:05 989  end bloc........true
isShutdown=true____isTerminated=true
11
 
1
java.lang.InterruptedException: sleep interrupted
2
    at java.lang.Thread.sleep(Native Method)
3
    at Test$1.run(Test.java:20)
4
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
5
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
6
    at java.lang.Thread.run(Unknown Source)
7
2018.06.25 22:44:05 987  start block
8
2018.06.25 22:44:05 987  start run.................false
9
2018.06.25 22:44:05 989  end run
10
2018.06.25 22:44:05 989  end bloc........true
11
isShutdown=true____isTerminated=true

submit 方法
  • <T> Future<T>  submit(Callable<T> task)  提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
    • 该 Future 的 get 方法在成功完成时将会返回该任务的结果。
    • 如果想立即阻塞任务的等待,则可以使用 result = exec.submit(aCallable).get(); 形式的构造。
    • 注:Executors 类包括了一组方法,可以转换某些其他常见的类似于闭包的对象,例如,将 PrivilegedAction 转换为 Callable 形式,这样就可以提交它们了。
  • Future<?>  submit(Runnable task)  提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
  • <T> Future<T>  submit(Runnable task, T result)  提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
    • 参数:task - 要提交的任务;result - 返回的结果
ExecutorService pool = Executors.newFixedThreadPool(1);
Callable<Long> callable = () -> {
   Long time = 1000L;
   try {
      Thread.sleep(time);
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
   return time;
};

try {
	System.out.println(System.currentTimeMillis() + "		start submit");//1530177340967		start submit
	Future<Long> future = pool.submit(callable);//不阻塞,只是将任务提交,并不会执行任务
	System.out.println(System.currentTimeMillis() + "		end submit");//1530177340968		end submit
	Long result = future.get();//会阻塞,直到任务执行完毕
	System.out.println(System.currentTimeMillis() + "		result:" + result);//1530177341969		result:1000
} catch (InterruptedException | ExecutionException e) {
   e.printStackTrace();
}
20
20
 
1
ExecutorService pool = Executors.newFixedThreadPool(1);
2
Callable<Long> callable = () -> {
3
   Long time = 1000L;
4
   try {
5
      Thread.sleep(time);
6
   } catch (InterruptedException e) {
7
      e.printStackTrace();
8
   }
9
   return time;
10
};
11
12
try {
13
    System.out.println(System.currentTimeMillis() + "       start submit");//1530177340967      start submit
14
    Future<Long> future = pool.submit(callable);//不阻塞,只是将任务提交,并不会执行任务
15
    System.out.println(System.currentTimeMillis() + "       end submit");//1530177340968        end submit
16
    Long result = future.get();//会阻塞,直到任务执行完毕
17
    System.out.println(System.currentTimeMillis() + "       result:" + result);//1530177341969      result:1000
18
} catch (InterruptedException | ExecutionException e) {
19
   e.printStackTrace();
20
}

invoke 方法
  • <T> List<Future<T>>  invokeAll(Collection<? extends Callable<T>> tasks)  执行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表。
    • 返回列表的所有元素的 Future.isDone() 为 true
    • 注意,可以正常地或通过抛出异常来终止 已完成 任务。
    • 如果正在进行此操作时修改了给定的 collection,则此方法的结果是不确定的。
    • 参数:tasks - 任务 collection
    • 返回:表示任务的 Future 列表,列表顺序与给定任务列表的迭代器所生成的顺序相同,每个任务都已完成。
  • <T> List<Future<T>>  invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)  执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。
    • 返回列表的所有元素的 Future.isDone() 为 true。一旦返回后,即取消尚未完成的任务。(其他同上)
    • 返回:表示任务的 Future 列表,列表顺序与给定任务列表的迭代器所生成的顺序相同。如果操作未超时,则已完成所有任务;如果确实超时了,则某些任务尚未完成。

  • <T> T  invokeAny(Collection<? extends Callable<T>> tasks)  执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。
    • 一旦正常或异常返回后,则取消尚未完成的任务
    • 如果此操作正在进行时修改了给定的 collection,则此方法的结果是不确定的。
    • 返回:某个任务返回的结果
  • <T> T  invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)  执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果。(其他同上)
Collection<Callable<Long>> tasks = new ArrayList<Callable<Long>>();
tasks.add(callable);
tasks.add(callable);
try {
	System.out.println(System.currentTimeMillis() + "		start invokeAll");//1530177912367		start invokeAll
	List<Future<Long>> futures = pool.invokeAll(tasks);//阻塞,直到所有任务完成
	System.out.println(System.currentTimeMillis() + "		end invokeAll");//1530177914370		end invokeAll
	for (Future<Long> future : futures) {
		System.out.println(System.currentTimeMillis() + "		result:" + future.get());//不会阻塞,因为任务已经完成
        //这里会连续两次打印(如果后面的任务超时了,则返回的结果不会包含超时未完成的那些任务) 1530177914370		result:1000
	}
} catch (InterruptedException | ExecutionException e) {
	e.printStackTrace();
}
x
1
Collection<Callable<Long>> tasks = new ArrayList<Callable<Long>>();
2
tasks.add(callable);
3
tasks.add(callable);
4
try {
5
    System.out.println(System.currentTimeMillis() + "       start invokeAll");//1530177912367       start invokeAll
6
    List<Future<Long>> futures = pool.invokeAll(tasks);//阻塞,直到所有任务完成
7
    System.out.println(System.currentTimeMillis() + "       end invokeAll");//1530177914370     end invokeAll
8
    for (Future<Long> future : futures) {
9
        System.out.println(System.currentTimeMillis() + "       result:" + future.get());//不会阻塞,因为任务已经完成
10
        //这里会连续两次打印(如果后面的任务超时了,则返回的结果不会包含超时未完成的那些任务) 1530177914370      result:1000
11
    }
12
} catch (InterruptedException | ExecutionException e) {
13
    e.printStackTrace();
14
}

ScheduledExecutorService 延迟

public interface ScheduledExecutorService  extends  ExecutorService
1
1
 
1
public interface ScheduledExecutorService  extends  ExecutorService
所有超级接口: Executor, ExecutorService
所有已知实现类: ScheduledThreadPoolExecutor

一个 ExecutorService,可安排在给定的 延迟后运行或 定期执行的命令。

schedule 方法使用各种延迟创建任务,并返回一个 可用于取消或检查执行的任务对象
scheduleAtFixedRate 和 scheduleWithFixedDelay 方法创建并执行某些在取消前一直定期运行的任务。

用 Executor.execute(java.lang.Runnable) 和 ExecutorService 的 submit 方法所提交的命令,通过所请求的 0 延迟进行安排。schedule 方法中允许出现 0 和负数延迟(但不是周期),并将这些视为一种立即执行的请求。

所有的 schedule 方法都接受 相对延迟和周期作为参数,而不是绝对的时间或日期。将以 Date 所表示的绝对时间转换成要求的形式很容易。例如,要安排在某个以后的 Date 运行,可以使用:schedule(task, date.getTime() - System.currentTimeMillis(), TimeUnit.MILLISECONDS)。但是要注意,由于网络时间同步协议、时钟漂移或其他因素的存在,因此相对延迟的期满日期不必与启用任务的当前 Date 相符。 

Executors 类为此包中所提供的 ScheduledExecutorService 实现提供了便捷的工厂方法。
ScheduledExecutorService的主要作用就是可以将定时任务与线程池功能结合使用。

方法
  • ScheduledFuture<?>  schedule(Runnable command, long delay, TimeUnit unit)  创建并执行在给定延迟后启用的一次性操作。
    • 返回:表示挂起任务完成的 ScheduledFuture,并且其 get() 方法在完成后将返回 null
  • <V> ScheduledFuture<V>  schedule(Callable<V> callable, long delay, TimeUnit unit)  创建并执行在给定延迟后启用的 ScheduledFuture。
    • 参数:callable - 要执行的功能;delay - 从现在开始延迟执行的时间;unit - 延迟参数的时间单位
    • 返回:可用于提取结果或取消的 ScheduledFuture
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
ScheduledFuture<String> scheduledFuture = scheduler.schedule(callable, 1000, TimeUnit.MILLISECONDS);
x
 
1
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
2
ScheduledFuture<String> scheduledFuture = scheduler.schedule(callable, 1000, TimeUnit.MILLISECONDS);
  • ScheduledFuture<?>  scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)  创建并执行一个在给定初始延迟后首次启用的定期操作,后续操作具有给定的周期。
    • 也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推。
    • 如果任务的任何一个执行遇到异常,则后续执行都会被取消。否则,只能通过执行程序的取消或终止方法来终止该任务
    • 如果此任务的任何一个执行要花费比其周期更长的时间,则将推迟后续执行,但不会同时执行
    • 返回:表示挂起任务完成的 ScheduledFuture,并且其 get() 方法在取消后将抛出异常
  • ScheduledFuture<?>  scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)  创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。
    • 如果任务的任一执行遇到异常,就会取消后续执行。否则,只能通过执行程序的取消或终止方法来终止该任务。
    • 返回:表示挂起任务完成的 ScheduledFuture,并且其 get() 方法在取消后将抛出异常
//使用 scheduleAtFixedRate() 方法实现周期性执行,立刻执行,而且每隔1秒执行一次:
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);
 
1
//使用 scheduleAtFixedRate() 方法实现周期性执行,立刻执行,而且每隔1秒执行一次:
2
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);

Callable<V>

public interface Callable<V>
1
1
 
1
public interface Callable<V>
类型参数: V - call 方法的结果类型

所有已知子接口: JavaCompiler.CompilationTask

返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。
Callable 接口类似于 Runnable,两者都是为那些其实例可能 被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常
Executors 类包含一些从其他普通形式转换成 Callable 类的实用方法。

V call()   计算结果,如果无法计算结果,则抛出一个异常。
  • 返回:计算的结果
  • 抛出:Exception - 如果无法计算结果

Delayed

public interface Delayed extends Comparable<Delayed>
1
1
 
1
public interface Delayed extends Comparable<Delayed>
所有超级接口: Comparable< Delayed>
所有已知子接口: RunnableScheduledFuture<V>, ScheduledFuture<V>

一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象。
此接口的实现必须定义一个 compareTo 方法,该方法提供与此接口的 getDelay 方法一致的排序。

long getDelay(TimeUnit unit)    返回与此对象相关的剩余延迟时间,以给定的时间单位表示。
  • 参数:unit - 时间单位
  • 返回:剩余延迟时间;零或负值指示延迟时间已经用尽

2018-6-20




猜你喜欢

转载自www.cnblogs.com/baiqiantao/p/9240264.html
今日推荐