FutureTask如何进行异步计算

8
new Thread(new Runnable() {
           public void run() {
                 .............
                 .............
                 .............
    }
}).start();

如果我在主线程中执行这个操作,它将创建一个新线程并提交任务进行异步计算。
如果您查看FutureTask documentation,它也说:
可取消的异步计算。该类提供了Future的基本实现,具有启动和取消计算、查询计算是否完成以及检索计算结果的方法。
那么,FutureTask如何成为异步计算?它是否在内部创建线程并在实例化FutureTask时提交我们提供的任务?
FutureTask f = new FutureTask(new MyCallable());

否则它就不能是异步计算,请提供来自FutureTask 源代码的代码片段,在其中将任务提交给线程,以使其成为异步计算。谢谢。
我得到了答案。基本上是试图在与调用者相同的线程中运行任务。这在给定的代码中非常明显:
当您调用futureTask.run()时,它只会调用sync.innerRun();,而sync是内部类Sync的实例。在其中,它仅仅在同一线程中的可调用对象上调用call()
void innerRun() {
        if (!compareAndSetState(READY, RUNNING))
            return;

        runner = Thread.currentThread(); //here it is getting the current thread
        if (getState() == RUNNING) { 
            V result;
            try {
                result = callable.call();//here calling call which executes in the caller thread.
            } catch (Throwable ex) {
                setException(ex);
                return;
            }
            set(result);
        } else {
            releaseShared(0); // cancel
        }
    }

FutureTask<V> 实现了 RunnableFuture<V> 接口,因此它本身也是一个 Runnable - m0skit0
1个回答

8
那么FutureTask是一种异步计算方式,它会在实例化时内部创建线程并提交我们给它的任务,例如: FutureTask 不是直接由用户使用的。它被设计为通过 ExecutorService 接口及其实现类来使用的。这些类使用 FutureTask 并分叉线程等等... 您可能需要阅读有关如何使用 ExecutorService 并发类 的更多信息。 ThreadPoolExecutor 类是实际上执行线程池管理的主要类。通常您可以调用 Executors.newCachedThreadPool()Executors.newFixedThreadPool(10) 来获取它的一个实例。
// create a thread pool with 10 workers
ExecutorService threadPool = Executors.newFixedThreadPool(10);
// define your jobs somehow
for (MyCallable job : jobsToDo) {
    // under the covers this creates a FutureTask instance
    Future future = threadPool.submit(job);
    // save the future if necessary in a collection or something
}
// once we have submitted all jobs to the thread pool, it should be shutdown
threadPool.shutdown();
// now we can go back and call `future.get()` to get the results from our jobs

从学术角度来看,TPE在实现上扩展了AbstractExecutorService,你可以在那里看到FutureTask类被用于管理线程池中的任务:

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}
...
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

TPE 中的代码非常复杂,不容易展示执行异步调用的“片段”。 TPE 会检查是否需要向线程池添加更多线程。将其提交到任务队列中,可以拒绝或接受它,然后线程将出队任务并在后台运行。


1
有时我们也会使用futureTask.run(),这不是异步任务计算吗?还是它只是在最终调用者所在的同一线程上运行? - Trying
1
FutureTask.run() 只是带有一些锁定的调用任务的 run() 方法。它不会分叉任何线程 @Trying。您不应直接调用它。 - Gray
没错,它直接在同一个线程中调用它。请查看“FutureTask”的源代码。 - Gray
你应该查阅ExecutorService类的相关内容,请参考:http://docs.oracle.com/javase/tutorial/essential/concurrency/exinter.html。 - Gray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接