今天看到《Java并发编程实战》第六章的时候,书中讲了利用Executor框架来实现多线程,平时Executor用得不多,今天顺带学习了一下,写出来总结总结。
两种多线程执行任务的策略:
1.串行执行,即每次线程运行完才会运行下一个线程。这种方法是线程安全的,但是效率低,吞吐量小
2.为每个任务开辟一个线程,例如为每个请求服务器的连接建立一个线程,这种方法开销大(频繁地创建和销毁线程消耗大量资源,线程之间互相争夺处理资源等)以及有稳定性因素(线程的数量限制)
为了可以实现线程重用,对线程进行统一的管理,控制线程的数量,采用了线程池的方法。
Executor接口
public interface Executor {
void execute(Runnable command);
}
只要传入Runnable接口,调用execute方法即可开启线程。
ExecutorService接口(继承自Executor)
public interface ExecutorService extends Executor {
void shutdown();
List shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
Future submit(Callable task);
Future submit(Runnable task, T result);
Future> submit(Runnable task);
List> invokeAll(Collection extends Callable> tasks)
throws InterruptedException;
List> invokeAll(Collection extends Callable> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
T invokeAny(Collection extends Callable> tasks)
throws InterruptedException, ExecutionException;
T invokeAny(Collection extends Callable> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
submit方法,可以传入Runnable接口和Callable接口,然后返回Future接口
利用Executors类的工厂方法来创建线程池,以下是Executors类提供的常用的工厂方法
1.public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。每当提交一个任务就创建一个线程,直到达到线程池的最大数量。
2.public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,如果线程池的规模超过了处理需求时,就会回收空闲的线程,而当需求增加时,则可以添加新的线程,线程池的规模不存在限制。
3.public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。可以确保任务在队列中串行执行(例如FIFO,LIFO,优先级)
4.public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个可以以延时或定时的方式执行任务的线程池,类似Timer。
例子:
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class ExecutorDemo{
public static void main(String[] args) {
//创建有5个线程的线程池
Executor executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++){
ExecutorTest e = new ExecutorTest(String.valueOf(i));
executor.execute(e);
}
//这里不知道如何结束,看完第七章再来补充
}
}
class ExecutorTest implements Runnable{
String name;
ExecutorTest(String name){
this.name = name;
}
@Override
public void run(){
System.out.println("I am Thread " + name);
}
}
为什么需要用Callalbe呢,因为Runnable不能返回结果或者抛出异常
Runnable接口
public interface Runnable {
public abstract void run();
}
run()方法中完成任务
Callable接口
public interface Callable {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
call()方法有返回结果,并且可以抛出Exception
RunnableFuture接口
public interface RunnableFuture extends Runnable, Future {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
Future接口 ,Future表示一个任务的生命周期,并提供了相应的方法来判断是否完成,是否取消,获取任务的结果,取消任务
public interface Future {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
get()方法可以返回结果,不过需要等待任务完成才有返回值
public class FutureTask implements RunnableFuture {
public FutureTask(Callable callable) {...}
public FutureTask(Runnable runnable, V result){...}
}
import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class FutureTaskDemo{
public static void main(String[] args) throws Exception{
for (int i = 0; i < 10; i++){
CallableTest c = new CallableTest(String.valueOf(i));
FutureTask future = new FutureTask(c);
new Thread(future).start();
String result = future.get(); //这里阻塞等待了
System.out.println(result);
}
}
}
//不需要返回结果时可以写Void
class CallableTest implements Callable{
String name;
CallableTest(String name){
this.name = name;
}
public String call() throws Exception{
return "I am Thread " + name;
}
}
import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class FutureTaskDemo{
public static void main(String[] args) throws Exception{
Executor exec = Executors.newFixedThreadPool(1);
CallableTest c = new CallableTest("master");
FutureTask future = new FutureTask(c);
exec.execute(future);
System.out.println(future.get());
}
}
//不需要返回结果时可以写Void
class CallableTest implements Callable{
String name;
CallableTest(String name){
this.name = name;
}
public String call() throws Exception{
return "I am Thread " + name;
}
}
import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
public class FutureTaskDemo{
public static void main(String[] args) throws Exception{
CallableTest c = new CallableTest("master");
ExecutorService exec = Executors.newFixedThreadPool(1);
Future future = exec.submit(c);
System.out.println(future.get());
}
}
//不需要返回结果时可以写Void
class CallableTest implements Callable{
String name;
CallableTest(String name){
this.name = name;
}
public String call() throws Exception{
return "I am Thread " + name;
}
}
——————————
2019.5.4 回头补上取消和终止Executor的部分