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模式——《14.Java中的Future模式》

13.ThreadPoolExecutor线程池之submit方法的更多相关文章

  1. 线程池中 submit()和 execute()方法有什么区别?(未完成)

    线程池中 submit()和 execute()方法有什么区别?(未完成)

  2. [转]ThreadPoolExecutor线程池的分析和使用

    1. 引言 合理利用线程池能够带来三个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 第 ...

  3. ThreadPoolExecutor 线程池的源码解析

    1.背景介绍 上一篇从整体上介绍了Executor接口,从上一篇我们知道了Executor框架的最顶层实现是ThreadPoolExecutor类,Executors工厂类中提供的newSchedul ...

  4. 论如何优雅的自定义ThreadPoolExecutor线程池

    更好的markDown阅读体验可直接访问我的CSDN博客:https://blog.csdn.net/u012881584/article/details/85221635 前言 线程池想必大家也都用 ...

  5. ThreadPoolExecutor线程池的分析和使用

    1. 引言 合理利用线程池能够带来三个好处. 第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 第 ...

  6. ThreadPoolExecutor 线程池浅析

    作为Executor框架中最核心的类,ThreadPoolExecutor代表着鼎鼎大名的线程池,它给了我们足够的理由来弄清楚它. 下面我们就通过源码来一步一步弄清楚它. 内部状态 线程有五种状态:新 ...

  7. j.u.c系列(01) ---初探ThreadPoolExecutor线程池

    写在前面 之前探索tomcat7启动的过程中,使用了线程池(ThreadPoolExecutor)的技术 public void createExecutor() { internalExecutor ...

  8. 线程池之ThreadPoolExecutor线程池源码分析笔记

    1.线程池的作用 一方面当执行大量异步任务时候线程池能够提供较好的性能,在不使用线程池的时候,每当需要执行异步任务时候是直接 new 一线程进行运行,而线程的创建和销毁是需要开销的.使用线程池时候,线 ...

  9. Java并发——ThreadPoolExecutor线程池解析及Executor创建线程常见四种方式

    前言: 在刚学Java并发的时候基本上第一个demo都会写new Thread来创建线程.但是随着学的深入之后发现基本上都是使用线程池来直接获取线程.那么为什么会有这样的情况发生呢? new Thre ...

随机推荐

  1. 深刻认识shift_ram IP core——图像处理学习笔记

    在进行图像处理算法中,往往需要生成图像像素矩阵,这对于C语言来说可以直接用数据表示,但是对于verilog来说便不是那么容易了,硬件描述语言不比软件,它的核心不再算法,而是在于设计思想,加速硬件.在进 ...

  2. bootstrap的常用组件和栅格式布局

    Bootstrap 是最受欢迎的 HTML.CSS 和 JS 框架,用于开发响应式布局.移动设备优先的 WEB 项目. 因为Bootstrap需要jquery的支持,所以在使用Bootstrap之前要 ...

  3. 蓝桥杯-买不到的数目-java

    /* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...

  4. Openstack Swift 原理、架构与 API 介绍

    OpenStack Swift 开源项目提供了弹性可伸缩.高可用的分布式对象存储服务,适合存储大规模非结构化数据.本文将深入介绍 Swift 的基本设计原理.对称式的系统架构和 RESTful API ...

  5. 全球移动互联网大会gmic 2017为什么值得参加?

    长城会CEO郝义认为,"科学产业化将会推动科学复兴,"而本次GMIC 北京 2017也将首次引入了高规格科学家闭门峰会,专门设置G-Summit全球科学创新峰会,以"科学 ...

  6. react native 升级到0.31.0的相关问题 mac xcode开发环境

    cmd + D和cmd + R快捷键没有反应 0.31.0版本换了一种加载方式,通过修改userDefaults达到debug目的 [userDefaults setObject:@"127 ...

  7. Vbs脚本实现radmin终极后门

    Vbs脚本实现radmin终极后门 代码如下: on error resume next const HKEY_LOCAL_MACHINE = &H80000002 strComputer = ...

  8. 自学JS

    通过慕课网自学JS,敲了好多代码,好像没什么卵用,附上代码,再接再厉吧! //属性getter setter方法var man = {name : 'wsy', weibo : '@wsy', get ...

  9. 全国各省市GeoCoord SQL文件(不包括区县)

    /* Navicat MySQL Data Transfer Source Server : 192.168.0.234 Source Server Version : 50543 Source Ho ...

  10. 8、单选按钮(JRadioButton)和复选框(JCheckBox)

    8.单选按钮(JRadioButton)和复选框(JCheckBox) 实现一个单选按钮(或复选框),此按钮项可被选择或取消选择,并显示其状态.JRadioButton对象与ButtonGroup对象 ...