• 首页
  • 首页
  • 乱系短篇合集合集儿媳
  • 靠b猛视频大全视频免费
  • 男女拍拍拍的全过程免费
  • 一个 Callable 接口能有多少知识点?

    发布日期:2022-01-13 13:05    点击次数:190

     

    并发编程不息是程序员们比较头疼的,如何编写精确的并发程序相比其他程序来说,是一件比较难得的事情,并发编程中展现的 Bug 往往也是稀奇诡异的。

    之因而说并发编程展现的 Bug 比较诡异,是由于在并发编程中,许多时候展现的 Bug 纷歧定能完善的复现出来,也就是说,并发编程的 Bug 是很难重现,很难追踪的。

    今天,冰河再次带幼友人们复盘下Callable接口,益了,进入今天的正题。

    本文纯干货,从源码角度深入解析Callable接口,期待行家踏下心来,掀开你的IDE,跟着文章望源码,自夸你肯定收获不幼。

    Callable接口介绍

    Callable接口是JDK1.5新添的泛型接口,在JDK1.8中,被声明为函数式接口,如下所示。

    @FunctionalInterface public interface Callable<V> {     V call() throws Exception; } 

    在JDK 1.8中只声明有一个手段的接口为函数式接口,函数式接口能够行使@FunctionalInterface注脚修饰,也能够不行使@FunctionalInterface注脚修饰。只要一个接口中只包含有一个手段,那么,这个接口就是函数式接口。

    在JDK中,实现Callable接口的子类如下图所示。

    默认的子类层级有关图望不清,这边,能够始末IDEA右键Callable接口,选择“Layout”来指定Callable接口的实现类图的分歧组织,如下所示。

    这边,能够选择“Organic Layout”选项,选择后的Callable接口的子类的组织如下图所示。

    在实现Callable接口的子类中,有几个比较主要的类,如下图所示。

    别离是:Executors类中的静态内部类:PrivilegedCallable、PrivilegedCallableUsingCurrentClassLoader、RunnableAdapter和Task类下的TaskCallable。

    Callable接口的实现类

    接下来,分析的类主要有:PrivilegedCallable、PrivilegedCallableUsingCurrentClassLoader、RunnableAdapter和Task类下的TaskCallable。固然这些类在实际做事中很少被直接用到,但是行为别名相符格的开发工程师,竖立是秃顶的资深行家来说,晓畅并掌握这些类的实现有助你进一步理解Callable接口,并挑高专科技能(头发再失踪一批,哇哈哈哈。。。)。

    PrivilegedCallable

    PrivilegedCallable类是Callable接口的一个稀奇实现类,它外明Callable对象有某栽特权来访问体系的某栽资源,PrivilegedCallable类的源代码如下所示。

    /**  * A callable that runs under established access control settings  */ static final class PrivilegedCallable<T> implements Callable<T> {  private final Callable<T> task;  private final AccessControlContext acc;   PrivilegedCallable(Callable<T> task) {   this.task = task;   this.acc = AccessController.getContext();  }   public T call() throws Exception {   try {    return AccessController.doPrivileged(     new PrivilegedExceptionAction<T>() {      public T run() throws Exception {       return task.call();      }     }, acc);   } catch (PrivilegedActionException e) {    throw e.getException();   }  } } 

    从PrivilegedCallable类的源代码来望,能够将PrivilegedCallable望成是对Callable接口的封装,并且这个类也继承了Callable接口。

    在PrivilegedCallable类中有两个成员变量,别离是Callable接口的实例对象和AccessControlContext类的实例对象,如下所示。

    private final Callable<T> task; private final AccessControlContext acc; 

    其中,AccessControlContext类能够理解为一个具有体系资源访问决策的上下文类,始末这个类能够访问体系的特定资源。始末类的组织手段能够望出,在实例化AccessControlContext类的对象时,只必要传递Callable接口子类的对象即可,如下所示。

    PrivilegedCallable(Callable<T> task) {  this.task = task;  this.acc = AccessController.getContext(); } 

    AccessControlContext类的对象是始末AccessController类的getContext()手段获取的,这边,查望AccessController类的getContext()手段,如下所示。

    public static AccessControlContext getContext(){  AccessControlContext acc = getStackAccessControlContext();  if (acc == null) {   return new AccessControlContext(null, true);  } else {   return acc.optimize();  } } 

    始末AccessController的getContext()手段能够望出,最先始末getStackAccessControlContext()手段来获取AccessControlContext对象实例。倘若获取的AccessControlContext对象实例为空,则始末调用AccessControlContext类的组织手段实例化,否则,调用AccessControlContext对象实例的optimize()手段返回AccessControlContext对象实例。

    这边,吾们先望下getStackAccessControlContext()手段是个什么鬼。

    private static native AccessControlContext getStackAccessControlContext(); 

    正本是个本地手段,手段的字面有趣就是获取能够访问体系栈的决策上下文对象。

    接下来,吾们回到PrivilegedCallable类的call()手段,如下所示。

    public T call() throws Exception {  try {   return AccessController.doPrivileged(    new PrivilegedExceptionAction<T>() {     public T run() throws Exception {      return task.call();     }    }, acc);  } catch (PrivilegedActionException e) {   throw e.getException();  } } 

    始末调用AccessController.doPrivileged()手段,传递PrivilegedExceptionAction。接口对象和AccessControlContext对象,并最后返回泛型的实例对象。

    最先,望下AccessController.doPrivileged()手段,如下所示。

    @CallerSensitive public static native <T> T     doPrivileged(PrivilegedExceptionAction<T> action,                  AccessControlContext context)     throws PrivilegedActionException; 

    能够望到,又是一个本地手段。也就是说,最后的实走情况是将PrivilegedExceptionAction接口对象和AccessControlContext对象实例传递给这个本地手段实走。并且在PrivilegedExceptionAction接口对象的run()手段中调用Callable接口的call()手段来实走最后的营业逻辑,并且返回泛型对象。

    PrivilegedCallableUsingCurrentClassLoader

    此类外示为在已经竖立的特定访问限制和现在的类添载器下运走的Callable类,源代码如下所示。

    /**  * A callable that runs under established access control settings and  * current ClassLoader  */ static final class PrivilegedCallableUsingCurrentClassLoader<T> implements Callable<T> {  private final Callable<T> task;  private final AccessControlContext acc;  private final ClassLoader ccl;   PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {   SecurityManager sm = System.getSecurityManager();   if (sm != null) {    sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);    sm.checkPermission(new RuntimePermission("setContextClassLoader"));   }   this.task = task;   this.acc = AccessController.getContext();   this.ccl = Thread.currentThread().getContextClassLoader();  }   public T call() throws Exception {   try {    return AccessController.doPrivileged(     new PrivilegedExceptionAction<T>() {      public T run() throws Exception {       Thread t = Thread.currentThread();       ClassLoader cl = t.getContextClassLoader();       if (ccl == cl) {        return task.call();       } else {        t.setContextClassLoader(ccl);        try {         return task.call();        } finally {         t.setContextClassLoader(cl);        }       }      }     }, acc);   } catch (PrivilegedActionException e) {    throw e.getException();   }  } } 

    这个类理解首来比较浅易,最先,在类中定义了三个成员变量,如下所示。

    private final Callable<T> task; private final AccessControlContext acc; private final ClassLoader ccl; 

    接下来,始末组织手段注入Callable对象,在组织手段中,最先获取体系坦然管理器对象实例,始末体系坦然管理器对象实例检查是否具有获取ClassLoader和竖立ContextClassLoader的权限。并在组织手段中为三个成员变量赋值,如下所示。

    PrivilegedCallableUsingCurrentClassLoader(Callable<T> task) {  SecurityManager sm = System.getSecurityManager();  if (sm != null) {   sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);   sm.checkPermission(new RuntimePermission("setContextClassLoader"));  }  this.task = task;  this.acc = AccessController.getContext();  this.ccl = Thread.currentThread().getContextClassLoader(); } 

    接下来,始末调用call()手段来实走详细的营业逻辑,如下所示。

    public T call() throws Exception {  try {   return AccessController.doPrivileged(    new PrivilegedExceptionAction<T>() {     public T run() throws Exception {      Thread t = Thread.currentThread();      ClassLoader cl = t.getContextClassLoader();      if (ccl == cl) {       return task.call();      } else {       t.setContextClassLoader(ccl);       try {        return task.call();       } finally {        t.setContextClassLoader(cl);       }      }     }    }, acc);  } catch (PrivilegedActionException e) {   throw e.getException();  } } 

    在call()手段中同样是始末调用AccessController类的本地手段doPrivileged,传递PrivilegedExceptionAction接口的实例对象和AccessControlContext类的对象实例。

    详细实走逻辑为:在PrivilegedExceptionAction对象的run()手段中获取现在线程的ContextClassLoader对象,倘若在组织手段中获取的ClassLoader对象与此处的ContextClassLoader对象是联相符个对象(不止对象实例相通,而且内存地址也相通),则直接调用Callable对象的call()手段返回效果。否则,将PrivilegedExceptionAction对象的run()手段中的现在线程的ContextClassLoader竖立为在组织手段中获取的类添载器对象,接下来,再调用Callable对象的call()手段返回效果。最后将现在线程的ContextClassLoader重置为之前的ContextClassLoader。

    RunnableAdapter

    RunnableAdapter类比较浅易,给定运走的义务和效果,运走给定的义务并返回给定的效果,源代码如下所示。

    /**  * A callable that runs given task and returns given result  */ static final class RunnableAdapter<T> implements Callable<T> {  final Runnable task;  final T result;  RunnableAdapter(Runnable task, T result) {   this.task = task;   this.result = result;  }  public T call() {   task.run();   return result;  } } 
    TaskCallable

    TaskCallable类是javafx.concurrent.Task类的静态内部类,TaskCallable类主要是实现了Callable接口并且被定义为FutureTask的类,并且在这个类中批准吾们阻截call()手段来更新task义务的状态。源代码如下所示。

    private static final class TaskCallable<V> implements Callable<V> {   private Task<V> task;  private TaskCallable() { }   @Override   public V call() throws Exception {   task.started = true;   task.runLater(() -> {    task.setState(State.SCHEDULED);    task.setState(State.RUNNING);   });   try {    final V result = task.call();    if (!task.isCancelled()) {     task.runLater(() -> {      task.updateValue(result);      task.setState(State.SUCCEEDED);     });     return result;    } else {     return null;    }   } catch (final Throwable th) {    task.runLater(() -> {     task._setException(th);     task.setState(State.FAILED);    });    if (th instanceof Exception) {     throw (Exception) th;    } else {     throw new Exception(th);    }   }  } } 

    从TaskCallable类的源代码能够望出,只定义了一个Task类型的成员变量。下面主要分析TaskCallable类的call()手段。

    当程序的实走进入到call()手段时,最先将task对象的started属性竖立为true,外示义务已经最先,并且将义务的状态挨次竖立为State.SCHEDULED和State.RUNNING,挨次触发义务的调度事件和运走事件。如下所示。

    task.started = true; task.runLater(() -> {  task.setState(State.SCHEDULED);  task.setState(State.RUNNING); }); 

    接下来,在try代码块中实走Task对象的call()手段,返回泛型对象。倘若义务异国被作废,则更新义务的缓存,将调用call()手段返回的泛型对象绑定到Task对象中的ObjectProperty对象中,其中,ObjectProperty在Task类中的定义如下。

    private final ObjectProperty value = new SimpleObjectProperty<>(this, "value"); 

    接下来,将义务的状态竖立为成功状态。如下所示。

    try {  final V result = task.call();  if (!task.isCancelled()) {   task.runLater(() -> {    task.updateValue(result);    task.setState(State.SUCCEEDED);   });   return result;  } else {   return null;  } } 

    倘若程序抛出了变态或者舛讹,会进入catch()代码块,竖立Task对象的Exception新闻并将状态竖立为State.FAILED,也就是将义务标记为战败。接下来,判定变态或舛讹的类型,倘若是Exception类型的变态,则直接强转为Exception类型的变态并抛出。否则,将变态或者舛讹封装为Exception对象并抛出,如下所示。

    catch (final Throwable th) {  task.runLater(() -> {   task._setException(th);   task.setState(State.FAILED);  });  if (th instanceof Exception) {   throw (Exception) th;  } else {   throw new Exception(th);  } } 

    益了,今天就到这边吧,行家学会了吗?吾是冰河,吾们下期见~~

    本文转载自微信公多号「冰河技术」,能够始末以下二维码关注。转载本文请有关冰河技术公多号。

    【编辑选举】

    鸿蒙官方战略配相符共建——HarmonyOS技术社区 详解Java8接口中引入Default关键字的内心因为 选举一个 Java 接口迅速开发框架 Go说话行使Gin框架开发邮件告警接口功能 进阶全栈的第一步:能实现这五栽接口 行使程序接口(API)坦然的入门指南