面试准备 -- 学习 Executor 框架(上)

Executor框架

还记得以前写线程的时候用如下代码:

//初级版中的战斗机
new Thread(()-> System.out.println("12313")).start();

//初级版
new Thread(new Runnable() {
   @Override
  public void run() {
    System.out.println("");
   }
}).start();

在后来重新学习多线程时,知道了 JDK 提供了 Executor 框架,可以让我们有效的管理和控制我们的线程,其实质也就是一个线程池。
下面我们来看看 Executor 框架的的关系图:
在这里插入图片描述

来看看 Executor 源码发现接口里面只有一个 execute(Runnable r) 方法

public interface Executor {
    void execute(Runnable command);
}

虽然 Executor 里十分简单,但是它却为提供了强大且灵活的异步任务执行框架提供了基础,它还提供了一种标准的方式将任务的提交过程和执行过程解耦开来,并用 Runnable 来标识任务。可能有人说夸张了,就一个方法,除了个接收 Runnable 接口的参数方法外,什么都没有。别急,我们再来看看 Executor 接口的子接口。

public interface ExecutorService extends Executor {
    //判断线程池中的所有线程是否执行完毕时候
    void shutdown();
    //关闭当前正在执行的任务,并返回没有执行的任务的清单
    List<Runnable> shutdownNow();
    //判断是否关闭成功
    boolean isShutdown();
    //关闭后所有任务都已完成,则返回true
    boolean isTerminated();
    //检测线程池是否关闭,关闭后返回true
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
    //下面是任务提交的方法
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);
    //剩余的代码是用于任务提交便利方法
}

ExecutorService 接口提供了对生命周期管理的方法,以及可跟踪一个或多个异步任务执行状况返回 Future 的方法。下面我们来写下简单代码看看线程池的生命周期:

/**
 * @Auther: Gentle
 * @Date: 2019/3/20 14:50
 * @Description:
 */
public class TestThreadPool {
    //构建线程池
    private  static final ExecutorService executorService = Executors.newScheduledThreadPool(2);
    
    public static void main(String[] args) throws InterruptedException {
    
       executorService.execute(new MyTask("1"));
       executorService.execute(new MyTask("2"));
       //关闭线程池
        shop();
        //关闭线程池,返回未启动任务的清单
        // shopNow(); //想测试的话先注释 stop() 方法,开启这个注释
        boolean b = executorService.awaitTermination(1000, TimeUnit.SECONDS);
        System.out.println(b);
    }
    
    //关闭线程池方法
    private static void shopNow(){
        System.out.println("准备拒绝接收任务");
        List<Runnable> runnables = executorService.shutdownNow();
        System.out.println(runnables);
    }

    private static void shop(){
        System.out.println("准备拒绝接收任务");
         executorService.shutdown();
    }

    //自定义线程
    static class MyTask implements Runnable{
        private String name;
        public MyTask(String name){
            this.name=name;
        }
        @Override
        public void run() {
            while (!executorService.isShutdown()){
                System.out.println("线程:"+name+"在执行任务");

            }
        }
    }

}

下图是我们使用 shopNow() 方法强制关闭的情况下返回的任务列表。
在这里插入图片描述

注意:

ExecutorService 中 awaitTermination() 和 isTerminated() 方法必须在 shutdown()或shutdownNow() 方法后执行,否则用于都返回 false。

上诉接口中涉及到的 Future 接口和 Callable 接口后面的篇章会继续介绍。

Executor框架的两级调度模型

Executor 的两级调度模型,第一次看的时候我也懵了,这是什么鬼?后来看了看了线程实现的关系图才明白。

简单来说,在Windows 系统和 Linux 系统里提供的是一对一的线程模型。一条 Java线程被一对一映射为本地操作系统线程中。当 java 线程启动时也会启动一条操作系统的线程,当线程终止时,对应的操作系统的线程也被回收。线程要执行任务时,操作系统会将线程分配给 CPU。

在我们写的 java 程序中,上层依靠 Executor 框架来调用任务,在下层,操作系统将这些线程分配 CPU 执行。
如下是该框架的两级调度模型图:
在这里插入图片描述

Executor框架的执行流程

这里我们先区分一下两种情况。
一种 Executor 框架中 execute() 方法是没有返回值的,调用了就交给线程池处理。
另一种是有返回值的,Executor 框架中 submit() 方法,调用后会返回 Future ,可以取到线程完成后返回的数据。

接下来我们看具体Executor框架的执行流程图:

在这里插入图片描述

首先我们在主线程创建好线程池,创建好 Runnable 对象或 Callable 对象。

接下来我们将创建好的对象调用 submit() 或 execute() 提交到 ExecutorServic 管理。

如果使用的是 execute() 方法,任务提交了就提交了。如果是使用的是 submit() 方法,我们可以使用 Future.get() 方法来获得线程执行完毕返回的数据。

由于篇幅有限,今天就先写到这里,接下来会继续深挖线程池。

程序人生,与君共勉~!

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值