简单谈谈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方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java 线程池详解及实例代码

    线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收. 所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁.如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因. 例如Android中常见到的很多通用组件一般都离不开"池"的概念,如各种图片

  • java 中ThreadPoolExecutor原理分析

    java 中ThreadPoolExecutor原理分析 线程池简介 Java线程池是开发中常用的工具,当我们有异步.并行的任务要处理时,经常会用到线程池,或者在实现一个服务器时,也需要使用线程池来接收连接处理请求. 线程池使用 JDK中提供的线程池实现位于java.util.concurrent.ThreadPoolExecutor.在使用时,通常使用ExecutorService接口,它提供了submit,invokeAll,shutdown等通用的方法. 在线程池配置方面,Executor

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

    jdk1.7.0_79 在上一篇<ThreadPoolExecutor线程池原理及其execute方法>中提到了线程池ThreadPoolExecutor的原理以及它的execute方法.本文解析ThreadPoolExecutor#submit. 对于一个任务的执行有时我们不需要它返回结果,但是有我们需要它的返回执行结果.对于线程来讲,如果不需要它返回结果则实现Runnable,而如果需要执行结果的话则可以实现Callable.在线程池同样execute提供一个不需要返回结果的任务执行,而对

  • ThreadPoolExecutor线程池的使用方法

    ThreadPoolExecutor ThreadPoolExecutor线程池,java提供开发框架,管理线程的创建.销毁.优化.监控等. 有4种不同的任务队列: 1.ArrayBlockingQueue:基于数组结构的任务队列.此队列按先进先出的原则对任务进行排序. 2.LinkedBlockingQueue:基于链表结构的任务队列.此队列也是按先进先出的原则对任务进行排序.但性能比ArrayBlockingQueue高. 3.synchronousQueue:不存储元素的任务队列.每个插入

  • ThreadPoolExecutor线程池原理及其execute方法(详解)

    jdk1.7.0_79 对于线程池大部分人可能会用,也知道为什么用.无非就是任务需要异步执行,再者就是线程需要统一管理起来.对于从线程池中获取线程,大部分人可能只知道,我现在需要一个线程来执行一个任务,那我就把任务丢到线程池里,线程池里有空闲的线程就执行,没有空闲的线程就等待.实际上对于线程池的执行原理远远不止这么简单. 在Java并发包中提供了线程池类--ThreadPoolExecutor,实际上更多的我们可能用到的是Executors工厂类为我们提供的线程池:newFixedThreadP

  • 简单聊一聊Java线程池ThreadPoolExecutor

    目录 简介 参数说明 如何创建线程池 拒绝策略 总结 简介 ThreadPoolExecutor是一个实现ExecutorService接口的线程池,ExecutorService是主要用来处理多线程任务的一个接口,通常比较简单是用法是由Executors工厂类去创建. 线程池主要解决了两个不同的问题: 在执行大量异步任务时,为了能够提高性能,通常会减少每个任务的调用开销. 提供了一系列多线程任务的管理方法,便于多任务执行时合理分配资源以及一些异常情况的处理.每个ThreadPoolExecut

  • 谈谈Java 线程池

    一.引言 池的概念大家并不陌生,数据库连接池.线程池等...大体来说,有三个优点: 降低资源消耗. 提高响应速度. 便于统一管理. 以上是 "池化" 技术的相同特点,至于他们之间的不同点这里不讲,两者都是为了提高性能和效率,抛开实际做连连看找不同,没有意义. 同样,类比于线程池来说: 降低资源消耗: 重复利用线程池中已经创建的线程,相比之下省去了线程创建和销毁的性能消耗. 提高响应速度: 当有任务创建时,不必等待线程创建,可以立即执行. 便于统一管理: 使用线程池,可以对线程统一管理,

  • Java详解使用线程池处理任务方法

    什么是线程池? 线程池就是一个可以复用线程的技术. 不使用线程池的问题: 如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能. 线程池常见面试题: 1.临时线程什么时候创建? 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建临时线程. 2.什么时候会开始拒绝任务? 核心线程和临时线程都在忙,任务队列也满了,新的任务过来的时候才会开始任务拒绝. 1.线程池处理Runnable任务

  • python中ThreadPoolExecutor线程池和ProcessPoolExecutor进程池

    目录 1.ThreadPoolExecutor多线程 <1>为什么需要线程池呢? <2>标准库concurrent.futures模块 <3>简单使用 <4>as_completed(一次性获取所有的结果) <5>map()方法 <6>wait()方法 2.ProcessPoolExecutor多进程 <1>同步调用方式: 调用,然后等返回值,能解耦,但是速度慢 <2>异步调用方式:只调用,不等返回值,可能存在

  • python多进程使用及线程池的使用方法代码详解

    多进程:主要运行multiprocessing模块 import os,time import sys from multiprocessing import Process class MyProcess(Process): """docstring for MyProcess""" def __init__(self, arg, callback): super(MyProcess, self).__init__() self.arg = a

  • 解决python ThreadPoolExecutor 线程池中的异常捕获问题

    问题 最近写了涉及线程池及线程的 python 脚本,运行过程中发现一个有趣的现象,线程池中的工作线程出现问题,引发了异常,但是主线程没有捕获异常,还在发现 BUG 之前一度以为线程池代码正常返回. 先说重点 这里主要想介绍 python concurrent.futuresthread.ThreadPoolExecutor 线程池中的 worker 引发异常的时候,并不会直接向上抛起异常,而是需要主线程通过调用concurrent.futures.Future.exception(timeou

  • 如何理解Java线程池及其使用方法

    目录 一.前言 二.总体的架构 三.研读ThreadPoolExecutor 3.1.任务缓存队列 3.2.拒绝策略 3.3.线程池的任务处理策略 3.4.线程池的关闭 3.5.源码分析 四.常见的四种线程池 4.1.newFixedThreadPool 4.2.newSingleThreadExecutor 4.3.newCachedThreadPool 4.4.newScheduledThreadPool 五.使用实例 5.1.newFixedThreadPool实例 5.2.newCach

随机推荐