当前位置: 首页 > 编程笔记 >

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

徐焱
2023-03-14
本文向大家介绍简单谈谈ThreadPoolExecutor线程池之submit方法,包括了简单谈谈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 {
  ...
  <T> Future<T> submit(Callable<T> task);
  <T> Future<T> submit(Runnable task, T result);
  <T> Future<T> submit(Runnable task);
  ...
}

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

//AbstractExecutorService
public abstract class AbstractExecutorService implements ExecutorService {
  ...
  public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
  }
  public <T> Future<T> submit(Runnable task, T result) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
  }
  public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerExeption();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask; 
  }
  ...
}

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

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

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

submit(Callable<T> task)

package com.threadpoolexecutor;

import java.util.concurrent.*;

/**
 * ThreadPoolExecutor#sumit(Callable<T> task)
 * Created by yulinfeng on 6/17/17.
 */
public class Sumit1 {

 public static void main(String[] args) throws ExecutionException, InterruptedException {
 Callable<String> callable = new Callable<String>() {
 public String call() throws Exception {
 System.out.println("This is ThreadPoolExetor#submit(Callable<T> task) method.");
 return "result";
 }
 };

 ExecutorService executor = Executors.newSingleThreadExecutor();
 Future<String> 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<Data> 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<T> ftask = newTaskFor(task);
execute(ftask);

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

//AbstractExecutorService#newTaskFor
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
  return new FutureTask<T>(callable);
}
  protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
  return new FutureTask<T>(runnable, value);
}

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

以上这篇简单谈谈ThreadPoolExecutor线程池之submit方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。

 类似资料:
  • 主要内容:1 submit方法,1.1 Future submit(Runnable),1.2 Future submit(Runnable T),1.3 Future submit(Callable< T >),2 FutureTask的原理,2.1 FutureTask的概述,2.2 FutureTask的重要属性,2.3 FutureTask的构造器,2.4 run核心方法,2.5 cancel取消任务,,,,,,详细介绍了ThreadPoolExecutor线程池的submit方法的源码

  • 本文向大家介绍Android之线程池ThreadPoolExecutor的简介,包括了Android之线程池ThreadPoolExecutor的简介的使用技巧和注意事项,需要的朋友参考一下 Android中的线程池ThreadPoolExecutor解决了单线程下载数据的效率慢和线程阻塞的的问题,它的应用也是优化实现的方式。所以它的重要性不言而喻,但是它的复杂性也大,理解上可能会有问题,不过作为

  • 本文向大家介绍浅谈python 线程池threadpool之实现,包括了浅谈python 线程池threadpool之实现的使用技巧和注意事项,需要的朋友参考一下 首先介绍一下自己使用到的名词: 工作线程(worker):创建线程池时,按照指定的线程数量,创建工作线程,等待从任务队列中get任务; 任务(requests):即工作线程处理的任务,任务可能成千上万个,但是工作线程只有少数。任务通过 

  • 主要内容:1 核心线程预启动,1.1 prestartCoreThread启动一条,1.2 prestartAllCoreThreads启动全部,2 关闭线程池,2.1 shutdown温和停止,2.2 shutdownNow立即停止,3 hook钩子方法,4 线程池信息获取,4.1 awaitTermination等待终止,4.2 getTaskCount计划任务数量,4.3 getActiveCount工作线程数量,,,,,,,,,,,前面的文章中,我们介绍了ThreadPoolExecut

  • 本文向大家介绍简单谈谈python中的多进程,包括了简单谈谈python中的多进程的使用技巧和注意事项,需要的朋友参考一下 进程是由系统自己管理的。 1:最基本的写法 2、实际上是通过os.fork的方法产生进程的 unix中,所有进程都是通过fork的方法产生的。 3、线程共享内存 进程不共享内存: 若想共享内存,需使用multiprocessing模块中的Queue 4、锁:仅是对于屏幕的共享

  • 本文向大家介绍简单谈谈json跨域,包括了简单谈谈json跨域的使用技巧和注意事项,需要的朋友参考一下 这一篇文章呢,主要是之前一直听别人讲json跨域跨域,但是还是一头雾水,只知其一,于是一怒之下,翻阅各种资料,如果有不正确的地方,劳烦指正一下^_^ 首先,先了解浏览器有一个很重要安全性限制,即为同源策略:不同域的客户端脚本在无明确授权的情况下不能读些对方资源。跨域也就是不同源~ 简单的说,只要