Java并发——Executor框架(一)

对看过的资料进行了整理,方便自己学习

来源:https://www.cnblogs.com/love-Stefanie/p/6728228.html

           https://www.cnblogs.com/MOBIN/p/5436482.html

1. Executor框架包括:

线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。

Executor框架从任务执行中解耦了任务的提交操作。

Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),

ExecutorService:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回Future的方法

AbstractExecutorService:ExecutorService执行方法的默认实现

ScheduledExecutorService:一个可定时调度任务的接口,能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。

ScheduledThreadPoolExecutor:继承ThreadPoolExecutor的ScheduledExecutorService实现,一个可定时调度任务的线程池

ThreadPoolExecutor:线程池,可以通过调用Executors以下静态工厂方法来创建线程池并返回一个ExecutorService对象

 2. 为什么要使用Executor框架?

其内部使用了线程池机制。好处如下:

(1)减少线程创建和销毁的次数,使线程可以多次复用,减少了创建线程所需要的开销

(2)可以根据系统情况,调整线程的数量。防止创建过多的线程,消耗过多的内存(每个线程1M左右)

3. Executor和ExecutorService

Executor:一个接口,其定义了一个接收Runnable对象的方法executor,其方法签名为executor(Runnable command),该方法接收一个Runable实例,它用来执行一个任务,任务即一个实现了Runnable接口的类,一般来说,Runnable任务开辟在新线程中的使用方法为:new Thread(new RunnableTask())).start(),但在Executor中,可以使用Executor而不用显示地创建线程:executor.execute(new RunnableTask()); // 异步执行

ExecutorService:是一个比Executor使用更广泛的子类接口,其提供了生命周期管理的方法,返回 Future 对象,以及可跟踪一个或多个异步任务执行状况返回Future的方法;可以调用ExecutorService的shutdown()方法来平滑地关闭 ExecutorService,调用该方法后,将导致ExecutorService停止接受任何新的任务且等待已经提交的任务执行完成(已经提交的任务会分两类:一类是已经在执行的,另一类是还没有开始执行的),当所有已经提交的任务执行完毕后将会关闭ExecutorService。因此我们一般用该接口来实现和管理多线程。

ExecutorService接口下的方法:

(1)execute(Runnable):从父类继承过来的方法

public class Demo1 {
    
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor(); //创建一个单线程
        executorService.execute(new Runnable() { //接收一个Runnable实例
            public void run() {
                System.out.println("Asynchronous task");
            }
        });
        executorService.shutdown();
    }
}

这个方法有个问题,就是没有办法获知task的执行结果。如果我们想获得task的执行结果,我们可以传入一个Callable的实例

(2)submit(Runnable)方法:返回一个Future对象,通过返回的Future对象,我们可以检查提交的任务是否执行完毕。

public class Demo2 {
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newSingleThreadExecutor(); //创建一个单线程
        Future future = executorService.submit(new Runnable() { //接收一个Runnable实例
            public void run() {
                System.out.println("Asynchronous task");
            }
        });
        System.out.println(future.get()); //任务执行结束返回null.
        executorService.shutdown();
    }

}

(3)submit(Callable):与submit(Callable)类似,也会返回一个Future对象,但是除此之外,submit(Callable)接收的是一个Callable的实现,Callable接口中的call()方法有一个返回值,可以返回任务的执行结果,而Runnable接口中的run()方法是void的,没有返回值。

public class Demo1 {
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newSingleThreadExecutor(); //创建一个单线程
        Future<Object> future = executorService.submit(new Callable<Object>() { //接收一个Callable实例
            public Object call() {
                System.out.println("Asynchronous task");
                return "Callable Result";
            }
        });
        System.out.println("future.get()="+future.get());
        executorService.shutdown();
    }
}

(4)invokeAny(...):方法接收的是一个Callable的集合,执行这个方法不会返回Future,但是会返回所有Callable任务中其中一个任务的执行结果。这个方法也无法保证返回的是哪个任务的执行结果,反正是其中的某一个。

public class Demo2 {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Set<Callable<String>> callables = new HashSet<Callable<String>>();
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result1";
            }
            
        });
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result2";
            }
            
        });
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result3";
            }
            
        });
        
        String result = executorService.invokeAny(callables);        
        System.out.println(result);
        executorService.shutdown();
    }

}

(5) invokeAll(...):与 invokeAny(...)类似也是接收一个Callable集合,但是前者执行之后会返回一个Future的List,其中对应着每个Callable任务执行后的Future对象。

public class Demo3 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Set<Callable<String>> callables = new HashSet<Callable<String>>();
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result1";
            }
            
        });
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result2";
            }
            
        });
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result3";
            }
            
        });
        
        List<Future<String>> futures = executorService.invokeAll(callables);    //返回一个Future的List集合    
        for(Future<String> future:futures){
            System.out.println("future.get()="+future.get());
        }
        executorService.shutdown();
    }
}

(6)shutdown():我们使用完成ExecutorService之后应该关闭它,否则它里面的线程会一直处于运行状态。

举个例子,如果的应用程序是通过main()方法启动的,在这个main()退出之后,如果应用程序中的ExecutorService没有关闭,这个应用将一直运行。之所以会出现这种情况,是因为ExecutorService中运行的线程会阻止JVM关闭。

如果要关闭ExecutorService中执行的线程,我们可以调用ExecutorService.shutdown()方法。在调用shutdown()方法之后,ExecutorService不会立即关闭,但是它不再接收新的任务,直到当前所有线程执行完成才会关闭,所有在shutdown()执行之前提交的任务都会被执行。

如果我们想立即关闭ExecutorService,我们可以调用ExecutorService.shutdownNow()方法。这个动作将跳过所有正在执行的任务和被提交还没有执行的任务。但是它并不对正在执行的任务做任何保证,有可能它们都会停止,也有可能执行完成。

4.总结Executor的局限性

(1)Executor接口仅仅关注Runnable接口。一个可运行任务是无法简单地向其调用者返回结果值的(因为Runnable的run()方法不会返回结果值);

注:java.lang.Runnable 一个可运行的任务。

       java.util.concurrent.Callable 一个可被调用的任务。

(2)Executor也没有提供一种方式来追踪正在执行的任务进程、取消正在执行的任务或者确定运行的任务什么时候结束执行;

(3)Executor无法执行一组可运行的任务;

(4)Executor也没有为应用程序提供一种关闭executor的方式(或者说更为正确的关闭executor)

而ExecutorService接口克服了Executor的局限性。

猜你喜欢

转载自blog.csdn.net/zhm1563550235/article/details/84333888
今日推荐