Callable接口简介 Callable接口是JDK1.5新增的泛型接口,在JDK1.8中,被指定为函数式接口,如下内容所示。在JDK 1.8中,只有包含一个方法的接口被称为函数式接口。函数式接口可以添加@FunctionalInterface注解,也可以不添加。当一个接口中只有一个方法时,该接口就被称为函数式接口。在JDK中,继承Callable接口的子类如下所示。
通常看不清楚默认的子类层次结构图。在这里,您可以右键单击IDEA中的Callable接口,选择"布局"选项来指定Callable接口实现类图的不同结构,具体如下。在这里,您可以选择"有机布局"选项,选中后,Callable接口的子类结构将呈现如下图所示。在实现Callable接口的子类中,存在一些比较重要的类,如下图所示。Executors类中的静态内部类分别是:PrivilegedCallable、PrivilegedCallableUsingCurrentClassLoader、RunnableAdapter,以及Task类下的TaskCallable。实现了
Callable接口的类
下一步,所要分析的类主要包括:PrivilegedCallable、PrivilegedCallableUsingCurrentClassLoader、RunnableAdapter以及Task类中的TaskCallable。尽管这些类在实际工作中并不常见,但作为一名合格的开发工程师,了解和掌握这些类的实现对于理解Callable接口并提升专业技能是有帮助的,哦不,头发要再掉一把了,哈哈哈哈。。。)。PrivilegedCallable
PrivilegedCallable类是Callable接口的一个特殊实现类,表明Callable对象具有特殊权限访问系统资源,其源代码如下。/** * 一个 可在 已 建立 的 访问 控制 设置 下 运行 的 可调用的 函数 */ 静态 最终 类 PrivilegedCallable<T> 实现 了 Callable<T> { 私有 最终 Callable<T> 任务; 私有 最终 AccessControlContext acc; PrivilegedCallable(Callable<T> 任务) { this.task = 任务; this.acc = AccessController.getContext(); } 公共 T 调用() 抛出 异常 { 尝试 { return AccessController.doPrivileged( 新 PrivilegedExceptionAction<T>() { 公共 T 运行() 抛出 异常 { return 任务.call(); } },从PrivilegedCallable类的源码来看,可以将PrivilegedCallable视为对Callable接口的封装,且该类也实现了Callable接口。在PrivilegedCallable类中,有两个成员变量,分别是Callable接口的实例对象和AccessControlContext类的实例对象。
在PrivilegedCallable类中有两个成员变量,分别是Callable接口的实例对象和AccessControlContext类的实例对象,如下所示。
private final Callable<T> task; private final AccessControlContext acc;
其中,AccessControlContext类可以理解为一个具有系统资源访问决策的上下文类,通过这个类可以访问系统的特定资源。可以从类的构造函数中观察到,当实例化AccessControlContext类的对象时,只需要传递Callable接口的子类实例即可,示例如下。
PrivilegedCallable(Callable
通过AccessController类的getContext()方法获取的对象是AccessControlContext类的实例。这里提供了AccessController类的getContext()方法的具体实现。
公共 静态 AccessControlContext getContext(){ AccessControlContext acc = getStackAccessControlContext(); 如果(acc == null) { return new AccessControlContext(null,AccessController的getContext()方法可看到,最初需要调用getStackAccessControlContext()方法获取AccessControlContext对象实例。若获取的AccessControlContext对象实例为空,则需通过调用AccessControlContext类的构造方法来实例化;反之,调用已有的AccessControlContext对象实例的optimize()方法以获取AccessControlContext对象实例。若获得的AccessControlContext对象实例为空,则通过调用AccessControlContext类的构造方法来实例化;否则,调用已有的AccessControlContext对象实例的optimize()方法来返回该对象实例。
现在,我们先来看看getStackAccessControlContext()方法到底是什么。private static native AccessControlContext getStackAccessControlContext();
原来是个本地方法,方法的字面意思就是获取能够访问系统栈的决策上下文对象。接着,我们来看PrivilegedCallable类中call()方法的定义,如下:public T call() throws Exception {\n try {\n return AccessController.doPrivileged(\n new PrivilegedExceptionAction
这个类代表了在已经建立的特定访问控制和当前类加载器下运行的 Ca下面是Llable类的源代码。
/** * 可调用 的 方法 在 已建立的 访问 控制 设置 和 当前 ClassLoader */ 静态 最终 类 PrivilegedCallableUsingCurrentClassLoader<T> 实现 Callable<T> { 私有的 最终的 Callable<T> 任务; 私有的 最终的 AccessControlContext acc; 私有的 最终的 ClassLoader ccl; PrivilegedCallableUsingCurrentClassLoader(Callable<T> 任务) { SecurityManager sm = System.getSecurityManager(); if (sm !if (p == null) {\n pcheckPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);\n pcheckPermission(new RuntimePermission("setContextClassLoader"));\
\nthis.task = task;\nthis.acc = AccessController.getContext();\nthis.ccl = Thread.currentThread().getContextClassLoader();\npublic T call() throws Exception {\n try {\n return AccessController.doPrivileged(\n new PrivilegedExceptionAction
接下来,在构造函数中注入Callable对象,在构造函数中,首先获得系统安全管理器对象实例,然后使用该对象实例检查是否具有获取ClassLoader和设置ContextClassLoader的权限。
私有最终的Callable<T>任务; 私有最终的AccessControlContext acc; 私有最终的ClassLoader ccl;
随后,通过构造函数注入Callable对象。在构造函数中,首先获取系统安全管理器的实例,通过该实例检查是否具有获取ClassLoader和设置ContextClassLoader权限。然后为三个成员变量赋值,如下所示。使用当前类加载器特权调用者(Callable<T>任务){任务}{{任务}{任务}SecurityManager{任务}sm{任务}={任务}System.getSecurityManager();{任务}{任务}如果{任务}(sm{任务}!if (p != null) {\n p.sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);\n p.sm.checkPermission(new RuntimePermission("setContextClassLoader"));\ \nthis.task = task;\nthis.acc = AccessController.getContext();\nthis.ccl = Thread.currentThread().getContextClassLoader();\n// 接下来,通过调用call()方法来执行特定的业务逻辑,具体操作如下。公共的方法调用()抛出异常。尝试内部。返回AccessController.doPrivileged(new PrivilegedExceptionAction
的具体执行逻辑是:在PrivilegedExceptionAction对象的run()方法中,获取当前线程的ContextClassLoader对象。如果在构造函数中获取的ClassLoader对象与当前的ContextClassLoader对象相同(不仅对象实例相同,而且内存地址也相同),则直接调用Callable对象的call()方法并返回结果。
的具体执行逻辑为:首先在PrivilegedExceptionAction对象的run()方法中,获取当前线程的ContextClassLoader对象。然后检查在构造方法中获取的ClassLoader对象是否与此处的ContextClassLoader对象相同(不仅对象实例相同,而且内存地址也相同)。若相同,则直接调用Callable对象的call()方法并返回结果。若不同,则将PrivilegedExceptionAction对象run() 方法中当前线程的ContextClassLoader设置为在构造方法中获取的类加载器对象。最后再调用Callable对象的call()方法并返回结果。将当前线程的ContextClassLoader恢复至之前的设置。
RunnableAdapter
RunnableAdapter类非常简单,它接受一个可运行的任务和一个结果,在运行这个任务后返回指定的结果。下面是源代码示例。/** * A 可以 运行 给定 任务 并返回 给定 结果 */ static final class RunnableAdapter<T> 实现 Callable<T> { 最终的 Runnable task; 最终的 T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T call() { task.run(); return result; } }
TaskCallable
是javafx.concurrent.Task类的内部静态类。TaskCallable类主要是实现了Callable接口并且被定义为FutureTask类,它允许我们拦截call()方法来更新任务状态。以下是源代码示例。以下是源代码。私有的 静态的 final的 类 TaskCallable<V> 实现 Callable<V> { 私有的 Task<V> 任务; 私有的 TaskCallable()@Override\npublic V call() throws Exception {\n task.started = true;\n \n task.runLater(() -> {\n task.setState(State.SCHEDULED);\n task.setState(State.RUNNING);\n });\n \n try {\n final V result = task.call();\n \n if (!task.isCancelled()) {\n task.setState(State.COMPLETED);\n task.set(value);\n }\n \n return result;\n } catch (Exception e) {\n if (!task.isCancelled()) {\n task.setException(e);\n task.setState(State.FAILED);\n }\n \n throw e;\n }\ task.如果被取消了,使用runLater(() -> {updateValue(result);setState(State.SUCCEEDED);}来更新值并设置状态为SUCCEEDED;最后返回result;否则返回null。在捕获到异常的情况下,使用runLater(() -> {_setException(th);setState(State.FAILED);}来设置异常并将状态设置为FAILED;如果异常属于Exception类,则抛出该异常;否则抛出新的Exception。 根据TaskCallable类的源代码可以看出,只有一个Task类型的成员变量被声明。接下来将主要研究TaskCallable类中的call()函数。接下来我们将重点分析TaskCallable类中call()方法的功能。当程序执行进入call()方法后,首先会将任务对象的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对象中。在Task类中,ObjectProperty的定义如下。
私有的 最终的 ObjectProperty 值 = 新建 SimpleObjectProperty<>(this, "值");
然后,将任务的状态更新为成功。如下所示。当尝试调用task.call()时,最终结果为result。task.如果(isCancelled()) { runLater(() -> { updateValue(result); setState(State.SUCCEEDED); }); return result; } else { return null; } }
在程序抛出异常或错误时,将进入catch()代码块。设定Task对象的异常信息,并将状态设定为State.FAILED,即将任务标记为失败状态。接着,需要对异常或错误的类型进行判断,如果是Exception类型的异常,就将其直接强制转换为Exception类型的异常然后抛出。在接下来的步骤中,需要识别异常或错误的类型。如果是Exception类型的异常,就将其直接转换为Exception类型并抛出。如果不是,就封装为Exception对象然后抛出,具体操作如下。
遇到问题时 (最后的Throwable类型) : task.runLater(() -> { task._setException(th); task.setState(State.FAILED); }); 如果 (th 是Exception的子类) { 抛出 (Exception)th; } 否则 { 抛出 新的Exception(th); } }
完成,今天就结束吧,大家都学会了吗?我叫冰河,我们下次再见~
这篇文章是从微信公众号“冰河技术”转载的,扫描下面的二维码就可以关注啦。我是冰河,我们下次再见。这篇文章来源于微信公众号「冰河技术」,可以扫描下方二维码关注。转载请联系「冰河技术」公众号。这是一串包含了
, 和 的字符序列。