1.Executor简介在Java5之后,并发编程引入了一堆新的API,用于启动、调度和管理线程。Executor框架是Java5引入的,它内部使用了线程池机制。它位于java.util.cocurrent包下。通过这个框架,可以控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java5之后,通过Executor启动线程比使用Thread的start方法要好。除了更容易管理和更高效(用线程池实现,节省开销)之外,还有一个关键点:它有助于避免这个Escape问题——如果我们在构造函数中启动一个线程,因为另一个任务可能先于开始执行构造函数结束,此时可以在构造函数中用Executor访问半初始化的对象。Executor框架包括:线程池、Executor、Executors、ExecutorService、CompletionService、Future、Callable等。在java代码中,Executor是一个只有一个方法的接口。publicinterfaceExecutor{/***Executesthegivencommandatsometimeinthefuture.Thecommand*mayexecuteinanewthread,inapooledthread,orinthecalling*thread,atthediscretionofthe{@codeExecutor}implementation.**@paramcommandtherunnabletask*@throwsRejectedExecutionExceptionifthistaskcannotbe*acceptedforexecution*@throwsNullPointerExceptionifcommandisnull*/voidexecute(Runnablecommand);}2、ExecutorServiceExecutorService是一个接口,继承Executor,除了execute(Runnablecommand)方法外,还扩展了其他方法:publicinterfaceExecutorServiceextendsExecutor{}voidshutdown();列表shutdownNow();布尔isShutdown();布尔isTerminated();booleanawaitTermination(longtimeout,TimeUnitunit)throwsInterruptedException;未来提交(可调用任务);//提交任务Futuresubmit(Runnabletask,Tresult);//提交任务Futuresubmit(Runnabletask);//提交任务List>invokeAll(Co收藏>任务)抛出InterruptedException;List>invokeAll(Collection>tasks,longtimeout,TimeUnitunit)throwsInterruptedException;TinvokeAny(Collection>tasks)throwsInterruptedException,ExecutionException;TinvokeAny(Collection>tasks,longtimeout,TimeUnitunit)throwsInterruptedException,ExecutionException,TimeoutException;2.1execute(Runnable)接收一个java.lang.Runnable对象作为参数,异步执行下面是使用ExecutorService执行Runnablepackagecom.app;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;publicclassExecutorTest{publicstaticvoidmain(String[]args){//创建一个固定大小的线程of10线程池ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);//执行一个任务。任务是newRunnable()对象executorService.execute(newRunnable(){@Overridepublicvoidrun(){Log.d(Thread.currentThread().getName());}});//关闭线程池executorService.shutdown();}}结果:pool-1-thread-1这样执行Runnable后是没有办法得到结果的,如果想得到运行后的返回值,就需要使用接收a的execute()方法可调用参数,下面会提到。2.2.submit(Runnable)方法submit(Runnable)也接收一个Runnable实现作为参数,但返回一个Future对象。这个Future对象可以用来判断Runnable是否已经执行完毕。下面是ExecutorService的submit()方法的一个例子:){//创建一个固定线程大小为10的线程池ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);//执行一个任务是newRunnable()对象Futurefuture=executorService.submit(newRunnable(){@Overridepublicvoidrun(){Log.d(Thread.currentThread().getName());}});try{//如果任务结束,返回nullLog.d(""+future.get());}catch(Exceptione){e.printStackTrace();}//关闭线程池executorService.shutdown();}}Result:pool-1-thread-1null2.3submit(Callable)方法submit(Callable)与方法submit(Runnable)类似,但不同的是原因在于它们接受不同的参数类型。Callable的实例类似于Runnable的实例,但Callable的call()方法可以返回一个结果。Runnable.run()方法无法返回结果。Callable的返回值可以从方法submit(Callable)返回的Future对象中获取。以下是ExecutorServiceCallable的示例:[]args){//创建一个固定大小为10个线程的线程池ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);//执行一个任务是newCallable()objectFuturefuture=executorService.submit(newCallable(){@OverridepublicStringcall()throwsException{return"executed";}});try{//如果任务结束,返回Log.d("Theresultis:"+future.get());}catch(Exceptione){e.printStackTrace();}//关闭线程池executorService.shutdown();}}结果:结果为:执行完成2.4。inVokeAny()方法invokeAny()接收一个包含Callable对象的集合作为参数。调用该方法并不会返回Future对象,而是返回集合中一个Callable对象的结果,并且不能保证调用后返回的结果是哪个Callable,只能保证是这些中执行完毕的Callable对象可调用对象。如果任务完成或抛出异常,该方法将取消其他Callable的执行。packagecom.app;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;publicclassExecutorTest{publicstaticvoidmain(String[]args){//创建一个固定大小为10个线程的线程池ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);List>list=newArrayList<>();//Create***CallableCallablecallable1=newCallable(){@OverridepublicStringcall()throwsException{Log.d("callable1线程是:"+Thread.currentThread().getName());返回“callable1被执行”;}};//创建第二个CallableCallablecallable2=newCallable(){@OverridepublicStringcall()throwsException{Log.d("callable2threadis:"+Thread.currentThread().getName());return"callable2hasbeenexecuted";}};list.add(callable1);list.add(callable2);try{Stringresult=executorService.invokeAny(list);Log.d("Theresultis:"+result);}catch(InterruptedExceptione1){e1.printStackTrace();}catch(ExecutionExceptione1){e1.printStackTrace();}//关闭线程池executorService.shutdown();}}Result:callable1threadis:pool-1-thread-1callable2threadis:pool-1-thread-2结果是:callable2总结:1.可以看到Callable中的call方法在sub-thread2.executorService.invokeAny(列表);返回值是任意一个Callable返回值,具体是哪一个,每一个都是可能的。2.5.invokeAll()方法invokeAll()会调用参数集合中存在的所有Callable对象,并返回一个包含Future对象的集合,你可以通过这个返回的集合来管理每个Callable的执行结果。需要注意的是,任务可能会因为异常而结束,所以不一定真的运行成功。但是我们没有办法通过Future对象知道这个区别。packagecom.app;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;publicclassExecutorTest{publicstaticvoidmain(String[]args){//创建一个固定大小为10个线程的线程池ExecutorServiceexecutorService=Executors.newFixedThreadPool(10);List>list=newArrayList<>();//Create***CallableCallablecallable1=newCallable(){@OverridepublicStringcall()throwsException{Log.d("callable1线程是:"+Thread.currentThread().getName());返回“callable1被执行”;}};//创建第二个CallableCallablecallable2=newCallable(){@OverridepublicStringcall()throwsException{Log.d("callable2threadis:"+Thread.currentThread().getName());return"executedcallable2";}};list.add(callable1);list.add(callable2);List>result;try{result=executorService.invokeAll(list);for(Futurefuture:result){Log.d("结果是:"+future.get());}}catch(Exceptione){e.printStackTrace();}//关闭线程池executorService.shutdown();}}结果callable1线程为:pool-1-thread-1callable2线程为:pool-1-thread-2结果为:callable1被执行了resultis:callable2isexecuted注意:1:Callable的call方法是在子线程中执行的2:executorService.invokeAll(list)是返回值但是必须在所有Callable对象都执行完毕后才返回。返回值是一个列表,顺序和ListSamefor。在执行过程中,如果出现任何Callable异常,程序将崩溃且没有返回值。2.6如何关闭ExecuteService服务?使用完ExecutorService后,我们应该关闭它,这样才能保证线程不会继续运行。例如,如果你的程序是用main()方法启动的,主线程退出你的程序,如果你的程序中还有一个活跃的ExecutorService,那么程序会继续运行。ExecutorService中存在的活动线程阻止Java虚拟机关闭。为了关闭ExecutorService中的线程,您需要调用shutdown()方法。ExecutorService不会立即关闭,但不会再接收新的任务。一旦所有线程执行完当前任务,ExecutorServie就会真正关闭。在调用shutdown()方法之前提交给ExecutorService的所有任务都会被执行。如果您希望立即关闭ExecutorService,可以调用shutdownNow()方法。该方法将尝试立即关闭所有正在运行的任务,并跳过所有已提交但尚未运行的任务。但是对于正在执行的任务,并不能保证能不能成功关闭。有可能他们真的关闭了,也可能会一直执行到任务结束。这是一个很好的尝试。