简单谈谈ThreadPoolExecutor线程池之submit方法

网友投稿 671 2023-05-06


简单谈谈ThreadPoolExecutor线程池之submit方法

jdk1.7.0_79

在上一篇《ThreadPoolExecutor线程池原理及其execute方法》中提到了线程池ThreadPoolExecutor的原理以及它的execute方法。本文解析ThreadPoolExecutor#submit。

对于一个任务的执行有时我们不需要它返回结果,但是有我们需要它的返回执行结果。对于线程来讲,如果不需要它返回结果则实现Runnable,而如果需要执行结果的话则可以实现Callable。在线程池同样execute提供一个不需要返回结果的任务执行,而对于需要结果返回的则可调用其submit方法。

回顾ThreadPoolExecutor的继承关系。

在Executor接口中只定义了execute方法,而submit方法则是在ExecutorService接口中定义的。

//ExecutorService

public interface ExecutorService extends Executor {

  ...

   Future submit(Callable task);

   Future submit(Runnable task, T result);

   Future submit(Runnable task);

  ...

}

而在其子类AbstractExecutorService实现了submit方法。

//AbstractExecutorService

public abstract class AbstractExecutorService implements ExecutorService {

  ...

  public Future submit(Callable task) {

    if (task == null) throw new NullPointerException();

    RunnableFuture ftask = newTaskFor(task);

    execute(ftask);

    return ftask;

  }

  public Future submit(Runnable task, T result) {

    if (task == null) throw new NullPointerException();

    RunnableFuture ftask = newTaskFor(task);

    execute(ftask);

    return ftask;

  }

  public Future> submit(Runnable task) {

    if (task == null) throw new NullPointerExeption();

    RunnableFuture ftask = newTaskFor(task, null);

    execute(ftask);

    return ftask;

  }

  ...

}

在AbstractExecutorService实现的submit方法实际上是一个模板方法,定义了submit方法的算法骨架,其execute交给了子类。(可以看到在很多源码中,模板方法模式被大量运用,有关模板方法模式可参考《模板方法模式》)

尽管submit方法能提供线程执行的返回值,但只有实现了Callable才会有返回值,而实现Runnable的线程则是没有返回值的,也就是说在上面的3个方法中,submit(Callable task)能获取到它的返回值,submit(Runnable task, T result)能通过传入的载体result间接获得线程的返回值或者准确http://来说交给线程处理一下,而最后一个方法submit(Runnable task)则是没有返回值的,就算获取它的返回值也是null。

下面给出3个例子,来感受下submit方法。

submit(Callable task)

package com.threadpoolexecutor;

import jcROhpHava.util.concurrent.*;

/**

* ThreadPoolExecutor#sumit(Callable task)

* Created by yulinfeng on 6/17/17.

*/

public class Sumit1 {

public static void main(String[] args) throws ExecutionException, InterruptedException {

Callable callable = new Callable() {

public String call() throws Exception {

System.out.println("This is ThreadPoolExetor#submit(Callable task) method.");

return "result";

}

};

ExecutorService executor = Executors.newSingleThreadExecutor();

Future future = executor.submit(callable);

System.out.println(future.get());

}

}

submit(Runnable task, T result)

package com.threadpoolexecutor;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

/**

* ThreadPoolExecutor#submit(Runnable task, T result)

* Created by yulinfeng on 6/17/17.

*/

public class Submit2 {

public static void main(String[] args) throws ExecutionException, InterruptedException {

ExecutorService executor = Executors.newSingleThreadExecutor();

Data data = new Data();

Future future = executor.submit(new Task(data), data);

System.out.println(future.get().getName());

}

}

class Data {

String name;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

}

class Task implements Runnable {

Data data;

public Task(Data data) {

this.data = data;

}

public void run() {

System.out.println("This is ThreadPoolExetor#submit(Runnable task, T result) method.");

data.setName("kevin");

}

}

submit(Runnable task)

package com.threadpoolexecutor;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

/**

* ThreadPoolExecutor#sumit(Runnable runnables)

* Created by yulinfeng on 6/17/17.

*/

public class Submit {

public static void main(String[] args) throws ExecutionException, InterruptedException {

Runnable runnable = new Runnable() {

public void run() {

System.out.println("This is ThreadPoolExetor#submit(Runnable runnable) method.");

}

};

ExecutorService executor = Executors.newSingleThreadExecutor();

Future future = executor.submit(runnable);

System.out.println(future.get());

}

}

通过上面的实例可以看到在调用submit(Runnable runnable)的时候是不需要其定义类型的,也就是说虽然在ExecutorService中对其定义的是泛型方法,而在AbstractExecutorService中则不是泛型方法,因为它没有返回值。(有关Object、T、?这三者的区别,可参考《Java中的Object、T(泛型)、?区别》)。

从上面的源码可以看到,这三者方法几乎是一样的,关键就在于:

RunnableFuture ftask = newTaskFor(task);

execute(ftask);

它是如何将一个任务作为参数传递给了newTaskFor,然后调用execute方法,最后进而返回ftask的呢?

//AbstractExecutorService#newTaskFor

protected RunnableFuture newTaskFor(Callable callable) {

  return new FutureTask(callable);

}

  protected RunnableFuture newTaskFor(Runnable runnable, T value) {

  return new FutureTask(runnable, value);

}

看来是返回了一个FutureTask实例,FutureTask实现了Future和Runnable接口。Future接口是Java线程Future模式的实现,可用用来异步计算,实现Runnable接口表示可以作为一个线程执行。FutureTask实现了这两个接口意味着它代表异步计算的结果,同时可以作为一个线程交给Executor来执行。有关FutureTask放到下章来单独解析。所以本文对于线程池ThreadPoolExecutor线程池的submit方法解析并不完整,必须得了解Java线程的Future模式——《老生常谈Java中的Future模式》。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:java<<、>>、>>>移位操作方法
下一篇:java HttpURLConnection 发送文件和字符串信息
相关文章

 发表评论

暂时没有评论,来抢沙发吧~