欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java中Callable和Future的區(qū)別

 更新時間:2022年11月21日 10:10:10   作者:iamswf  
這篇文章主要介紹了Java中Callable和Future的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

Java中為什么需要Callable

在java中有兩種創(chuàng)建線程的方法:

一種是繼承Thread類,重寫run方法:

public class TestMain {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        t1.start();
    }
}
class MyThread extends Thread {
    public void run() {
        System.out.println("MyThread running...");
    }
}

第二種是使用Runnable創(chuàng)建一個線程:

public class TestMain {
    public static void main(String[] args) {
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread created with runnable running...");
            }
        };
        Thread t1 = new Thread(r1);
        t1.start();
    }
}

其實(shí)這兩種方式,底層都是執(zhí)行Thread類的run方法:

無論使用這里的哪種方式創(chuàng)建線程,都無法在線程結(jié)束時return一個返回值。但是在非常多的場景下,我們都需要在線程執(zhí)行結(jié)束時,將執(zhí)行的結(jié)果封裝為一個返回值返回給主線程(或者調(diào)用者線程)。因此java在1.5版本時,在java.util.concurrent包引入了Callable接口,用于線程執(zhí)行完時return一個返回值。

Callable和Runnable的區(qū)別

Runnable和Callable都是接口,分別定義如下:

package java.lang;
?
/**
 * The <code>Runnable</code> interface should be implemented by any
 * class whose instances are intended to be executed by a thread. The
 * class must define a method of no arguments called <code>run</code>.
 * <p>
 * @since   JDK1.0
 */
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
package java.util.concurrent;
?
/**
 * A task that returns a result and may throw an exception.
 * Implementors define a single method with no arguments called
 * {@code call}.
 *
 * <p>The {@code Callable} interface is similar to {@link
 * java.lang.Runnable}, in that both are designed for classes whose
 * instances are potentially executed by another thread.  A
 * {@code Runnable}, however, does not return a result and cannot
 * throw a checked exception.
 *
 * <p>The {@link Executors} class contains utility methods to
 * convert from other common forms to {@code Callable} classes.
 *
 * @see Executor
 * @since 1.5
 * @author Doug Lea
 * @param <V> the result type of method {@code call}
 */
@FunctionalInterface
public interface Callable<V> {
    /**
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

可以看出,CallableRunnable主要有兩點(diǎn)區(qū)別:

  • 有返回值;
  • 可以拋出異常(這里拋出的異常,會在future.get()時可以通過ExectionException捕獲);

因此可以看出,Callable更加實(shí)用。這里舉個Callable使用的例子:

Callable callable = new Callable<Integer>() {
  @Override
  public Integer call() throws Exception {
    int i = new Random().nextInt(5);
    try {
      Thread.sleep(i * 1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    return i;
  }
};

雖然Callable接口的call方法可以返回執(zhí)行結(jié)果,但是有兩個問題需要解決:

  • 線程的創(chuàng)建只能通過Runnable,通過Callable又如何創(chuàng)建線程?
  • 如何獲取執(zhí)行結(jié)果?

答案是FutureRunnableFuture。

Future和RunnableFuture

Future是一個接口,看下定義:

package java.util.concurrent;
?
/**
 * A {@code Future} represents the result of an asynchronous
 * computation.  Methods are provided to check if the computation is
 * complete, to wait for its completion, and to retrieve the result of
 * the computation.  The result can only be retrieved using method
 * {@code get} when the computation has completed, blocking if
 * necessary until it is ready.  Cancellation is performed by the
 * {@code cancel} method.  Additional methods are provided to
 * determine if the task completed normally or was cancelled. Once a
 * computation has completed, the computation cannot be cancelled.
 * If you would like to use a {@code Future} for the sake
 * of cancellability but not provide a usable result, you can
 * declare types of the form {@code Future<?>} and
 * return {@code null} as a result of the underlying task.
 *
 * @see FutureTask
 * @see Executor
 * @since 1.5
 * @author Doug Lea
 * @param <V> The result type returned by this Future's {@code get} method
 */
public interface Future<V> {
?
    /**
     * Attempts to cancel execution of this task.  This attempt will
     * fail if the task has already completed, has already been cancelled,
     * or could not be cancelled for some other reason. If successful,
     * and this task has not started when {@code cancel} is called,
     * this task should never run.  If the task has already started,
     * then the {@code mayInterruptIfRunning} parameter determines
     * whether the thread executing this task should be interrupted in
     * an attempt to stop the task.
     *
     * <p>After this method returns, subsequent calls to {@link #isDone} will
     * always return {@code true}.  Subsequent calls to {@link #isCancelled}
     * will always return {@code true} if this method returned {@code true}.
     *
     * @param mayInterruptIfRunning {@code true} if the thread executing this
     * task should be interrupted; otherwise, in-progress tasks are allowed
     * to complete
     * @return {@code false} if the task could not be cancelled,
     * typically because it has already completed normally;
     * {@code true} otherwise
     */
    boolean cancel(boolean mayInterruptIfRunning);
?
    /**
     * Returns {@code true} if this task was cancelled before it completed
     * normally.
     *
     * @return {@code true} if this task was cancelled before it completed
     */
    boolean isCancelled();
?
    /**
     * Returns {@code true} if this task completed.
     *
     * Completion may be due to normal termination, an exception, or
     * cancellation -- in all of these cases, this method will return
     * {@code true}.
     *
     * @return {@code true} if this task completed
     */
    boolean isDone();
?
    /**
     * Waits if necessary for the computation to complete, and then
     * retrieves its result.
     *
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     */
    V get() throws InterruptedException, ExecutionException;
?
    /**
     * Waits if necessary for at most the given time for the computation
     * to complete, and then retrieves its result, if available.
     *
     * @param timeout the maximum time to wait
     * @param unit the time unit of the timeout argument
     * @return the computed result
     * @throws CancellationException if the computation was cancelled
     * @throws ExecutionException if the computation threw an
     * exception
     * @throws InterruptedException if the current thread was interrupted
     * while waiting
     * @throws TimeoutException if the wait timed out
     */
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

可以看出,Future可以用來表示線程的未來執(zhí)行結(jié)果:一個容器,這個容器內(nèi)將來存放的是線程的執(zhí)行結(jié)果,線程執(zhí)行完之前該容器內(nèi)沒有值,但是線程一旦執(zhí)行成功(Callablecall方法返回之后),就會將結(jié)果存入該容器。從Future的接口定義可看出,Future不僅支持阻塞獲取執(zhí)行結(jié)果,還支持取消任務(wù)的執(zhí)行,判斷任務(wù)是否執(zhí)行完成等。因此通過Future,主線程(或者調(diào)用者線程)可以跟進(jìn)子現(xiàn)場的執(zhí)行情況。

Callable其實(shí)和Runnable很像,都會執(zhí)行一個任務(wù),只不過Callable可以返回執(zhí)行的結(jié)果。一般將執(zhí)行結(jié)果封裝到Future,調(diào)用者線程即可以通過Future獲取Callable的執(zhí)行結(jié)果了。因此,一般Callable會和Future搭配使用。

但是問題來了:java創(chuàng)建線程,需要Runnable,獲取執(zhí)行結(jié)果又需要Future。因此RunnableFuture來了:

可以看出,通過RunnableFuture,既可以創(chuàng)建線程,又可以獲取線程的執(zhí)行結(jié)果,當(dāng)然RunnableFuture也是一個接口,我們一般情況下會使用它的具體實(shí)現(xiàn)類FutureTask。

那可能又有人要問了,Callable又是如何建立聯(lián)系的呢?看下FutureTask的使用方式就明白了:

public class TestMain {
    public static void main(String[] args) {
        Callable callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int i = new Random().nextInt(5);
                try {
                    Thread.sleep(i * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return i;
            }
        };
?
        /**
         * callable創(chuàng)建futureTask
         * FutureTask實(shí)現(xiàn)了RunnableFuture接口,因此即是Runnable又是Future
         * 作為Runnable可以傳入Thread創(chuàng)建線程并執(zhí)行
         * 作為Future,可以用來獲取執(zhí)行的結(jié)果。
         * 這里創(chuàng)建出來的futureTask對象有人稱為"具柄"或者"存根",大家可以理解為用來獲取線程執(zhí)行結(jié)果的一個"引用"即可。
         */
        FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
?
        // 作為Runnable使用
        Thread thread = new Thread(futureTask);
        thread.start();
?
        try {
            // 作為Future使用
            Integer integer = futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

因此FutureTaskCallableRunnable的橋梁。

不使用Callable和Future,僅使用Runnable實(shí)現(xiàn)相同功能

下面我們看下,如果不使用CallableFuture,僅使用Runnable如何實(shí)現(xiàn)返回值。

public class TestMain {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread t1 = new Thread(myRunnable);
        t1.start();
        Object o = myRunnable.get();
        System.out.println(o);
    }
}
?
class MyRunnable implements Runnable {
    // 存儲執(zhí)行結(jié)果
    private Object outCome = null;
?
    @Override
    public void run() {
        int i = new Random().nextInt(5);
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 存儲執(zhí)行結(jié)果
        outCome = i;
        // 產(chǎn)出結(jié)果后喚醒等待的get方法
        synchronized (this) {
            notifyAll();
        }
    }
?
    public synchronized Object get() {
        while(outCome == null) {
            try {
                // 等待產(chǎn)出結(jié)果
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return outCome;
    }
}

可以看出,通過Runnable實(shí)現(xiàn)更加麻煩,因此這也體現(xiàn)出了Callable+Future的優(yōu)勢。

以上就是詳解Java中Callable和Future的區(qū)別的詳細(xì)內(nèi)容,更多關(guān)于Java Callable Future區(qū)別的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論