Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand Callable interface in java

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces the relevant knowledge of "how to understand the Callable interface in java". Many people will encounter such a dilemma in the operation of actual cases, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

Callable, Executor and Future

Since a task is executed and the result is returned, let's first look at the specific task, that is, the Callable interface.

Task: Callable

Quite simply, it contains only a call () method with a generic "return value" that needs to return the result of the defined type at the end. If the task does not have a result that needs to be returned, set generic V to void and return null;. In contrast to Runnable, another obvious difference is that Callable can throw an exception.

Public interface Callable {V call () throws Exception;} public interface Runnable {public abstract void run ();}

Execute: ExecutorService

When it comes to threads, you can't do without thread pools, and when it comes to thread pools, you can't do without Executor interfaces. The following figure is the framework of Executor, where we often use two concrete implementation classes, ThreadPoolExecutor and ScheduledThreadPoolExecutor, which are obtained by static methods in the Executors class. Executors contains the construction of thread pools and thread factories, and the relationship to the Executor interface is similar to that of the Collection interface and the Collections class.

So let's take a top-down look at the Executor framework from the source code and learn how learning tasks are performed. The first is the Executor interface, where only the execute () method is defined.

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

The ExecutorService interface inherits the Executor interface and mainly extends a series of submit () methods as well as the termination and judgment of executor. Take the first Future submit (Callable task); as an example, where task is a user-defined asynchronous task, Future represents the execution result of the task, and generic T represents the type of task result.

Public interface ExecutorService extends Executor {void shutdown (); / / stop thread pool List shutdownNow () after the existing task is completed; / / stop thread pool boolean isShutdown () immediately; / / determine whether boolean isTerminated () has been stopped; Future submit (Callable task); / / submit Callale task Future submit (Runnable task, T result) Future submit (Runnable task); / / methods such as invokeAll () for Callable collections}

The abstract class AbstractExecutorService, the base class of ThreadPoolExecutor, implements the submit () method in the ExecutorService interface in the following code. In the comment is the code for the corresponding newTaskFor () method, which is very simple, encapsulating the incoming Callable or Runnable parameters into a FutureTask object.

/ / 1. The first overloaded method is Callable public Future submit (Callable task) {if (task = = null) throw new NullPointerException (); RunnableFuture ftask = newTaskFor (task); / / return new FutureTask (callable); execute (ftask); return ftask;} / / 2. The second overloaded method is Runnable public Future submit (Runnable task) {if (task = = null) throw new NullPointerException (); RunnableFuture ftask = newTaskFor (task, null); / / return new FutureTask (task, null); execute (ftask); return ftask;} / / 3. The third overloaded method. The parameter is Runnable + return object public Future submit (Runnable task, T result) {if (task = = null) throw new NullPointerException (); RunnableFuture ftask = newTaskFor (task, result); / / return new FutureTask (task, result); execute (ftask); return ftask;}

So, no matter whether the Callable or Runnable,submit () method is passed in, it actually does three things.

Specifically, the first person in submit () becomes an instance of FutureTask referenced by RunnableFuture, and then calls the execute () method to execute it, so we can speculate that FutureTask inherits from RunnableFuture, while RunnableFuture implements Runnable, because the parameter to execute () should be of type Runnable. The constructor of FutureTask is also involved, so let's take a look.

Public FutureTask (Callable callable) {this.callable = callable; this.state = NEW;} public FutureTask (Runnable runnable, V result) {this.callable = Executors.callable (runnable, result); / / execute runnable in call () through the adapter and return result this.state = NEW;}

There are two constructors for FutureTask. The first construction method is relatively simple. Corresponding to the first submit () above, we encapsulate Callable and set the state to NEW; in a combined way, while the second construction method corresponds to the last two submit () overloads above. The difference is that we first use Executors.callable to combine Runnable and result into Callable. Here we use the adapter RunnableAdapter implements Callable, which cleverly executes Runnable in call () and returns the result.

The result returned by static final class RunnableAdapter implements Callable {final Runnable task; final T result; / /; obviously: you need to assign RunnableAdapter (Runnable task, T result) {this.task = task; this.result = result;} public T call () {task.run (); return result;}} in run ()

In the adapter design pattern, there are usually three kinds of roles: the target interface Target, the adapter Adapter and the adaptor Adaptee, in which the target interface represents the functions required by the client (the current business system), usually an excuse or abstract class, and the adaptor is an existing class that can not meet the usage requirements. The adapter is a converter, also known as wrapper, which is used to add target functionality to the adaptor so that the client can correctly access it according to the format of the target interface. For RunnableAdapter, Callable is the target interface and Runnable is the adaptor. RunnableAdapter overrides the call () method so that it can be used in accordance with the requirements of Callable, and its construction method receives the adaptor and the target object, which meets the requirement that the call () method has a return value.

So to sum up the process executed by the submit () method, "Callable is encapsulated in a subclass of Runnable and execute () is passed in to execute."

Results: Future

It is not accurate to say that Future is the execution result of an asynchronous task, because it represents the execution process of a task, which is stateful and can be cancelled, while the return value of the get () method is the result of the task.

Public interface Future {boolean cancel (boolean mayInterruptIfRunning); boolean isCancelled (); boolean isDone (); V get () throws InterruptedException, ExecutionException; V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;}

We also mentioned RuunableFuture and FutureTask above. According to the official comments, RuunableFuture is a future that can be run, implementing Runnable and Future interfaces. When the calculation is finished in the run () method, the result should be saved so that it can be obtained through get ().

Public interface RunnableFuture extends Runnable, Future {/ * * Sets this Future to the result of its computation unless it has been cancelled. * / void run ();}

FutureTask directly implements the RunnableFuture API. As an execution process, there are the following states. COMPLETING is a temporary state, indicating that a result or exception is being set. Correspondingly, when the setting is completed, the status changes to NORMAL or EXCEPTIONAL;CANCELLED, and INTERRUPTED indicates that the task is cancelled or interrupted. In the construction method above, state is initialized to NEW.

Private volatile int state; private static final int NEW = 0; private static final int COMPLETING = 1; private static final int NORMAL = 2; private static final int EXCEPTIONAL = 3; private static final int CANCELLED = 4; private static final int INTERRUPTING = 5; private static final int INTERRUPTED = 6

Then there is the main content of FutureTask, mainly run () and get (). Note the comments in outcome, which returns this outcome whether an exception occurs or not, because the result is set to it (set ()) if the execution is successful, and the exception is assigned to him (setException ()) when an exception occurs, and outcome (through report ()) is returned when the result is obtained.

Public class FutureTask implements RunnableFuture {private Callable callable; / / target, the task to be executed / * * saves the execution result or exception, returns / throws * / private Object outcome; / / non-volatile in the get () method, and ensures thread safety through CAS public void run () {. Callable c = callable; if (c! = null & & state = = NEW) {V result; boolean ran; try {result = c.call (); / / call call () to execute the user task and get the result ran = true / / execution completed, ran set to true} catch (Throwable ex) {/ / call call () has an exception, while the run () method continues to execute result = null; ran = false; setException (ex) / / setException (Throwable t): compareAndSwapInt (NEW, COMPLETING); outcome = t;} if (ran) set (result); / / set (V v): compareAndSwapInt (NEW, COMPLETING); outcome = v }} public V get () throws InterruptedException, ExecutionException {int s = state; if (s = CANCELLED) throw new CancellationException (); throw new ExecutionException ((Throwable) x); / / return outcome as captured}}

FutureTask implements the RunnableFuture interface, so it works in two ways.

First, pass in the execute () method as Runnable, encapsulating the Callable object and calling its call () method in run ()

Second, as the execution state of the Future management task, the return value of call () is saved in outcome to be obtained through get (). This seems to answer the first two questions, and naturally, like a question, unless the exception returns not the result of the task but the exception object.

Summarize the inheritance relationship:

Second, use examples

The title of the article is a bit bluffing. In the final analysis, it still talks about the use of Callable. Now we know that Future represents the process and result of task execution, which is obtained as the return value of the call () method; while FutureTask is a Future of Runnable, which is not only the process and result of task execution, but also the carrier of the final execution of the call method. Let's look at the differences in their use through an example.

First create a task, that is, define a task class to implement the Callable interface, add our operation to the call () method, here it takes three seconds and then returns 100 to simulate the calculation process.

Class MyTask implements Callable {@ Override public Integer call () throws Exception {System.out.println ("the child thread starts to calculate..."); for (int iThreads)

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report