类图:


其实从类图我们能发现concurrent包(除去java.util.concurrent.atomic 和 java.util.concurrent.locks)中的内容并没有特别多,大概分为四类:BlockingQueue阻塞队列体系、Executor线程组执行框架、Future线程返回值体系、其他各种单独的并发工具等。

首先学习的是Executor体系,是我们处理多线程最常接触的内容。首先我们单独看下继承体系:

Executor是顶级接口,里面只有一个方法:


public interface Executor {
void execute(Runnable command);---执行一个Runnable对象,Runnable在前面的文章里面已经讲到,是线程的顶级接口,里面有个run方法
}

ExecutorService是我们经常用到的多线程执行框架的声明,源码也很少,我们逐个方法进行解释:

public interface ExecutorService extends Executor {
void shutdown();----关闭线程执行框架中的线程,但效果是不再接受新线程加入,并且等待线程执行结束后关闭Executor List<Runnable> shutdownNow();---大体同上的,但是该命令会尝试关闭正在运行中的线程,但是也仅仅是调用terminate方法然后让jdk去决定是否结束,同时该方法返回那些awaiting状态的线程组 boolean isShutdown();---是否已经被关闭的状态 boolean isTerminated();---是否已经被中止的状态,在shutdown和shutdownnow被调用后,并且线程全部执行结束,该状态才是true,否则都是false boolean awaitTermination(long timeout, TimeUnit unit) ---如果线程组terminate了,返回true,超时时间到了返回false。
throws InterruptedException; <T> Future<T> submit(Callable<T> task);--提交一个Callable的回调,然后执行完成后将结果放入Future对象。 <T> Future<T> submit(Runnable task, T result);--提交一个Runnable接口实现,然后result是Future返回值 Future<?> submit(Runnable task);--提交一个Runnable接口实现,如果执行完成,future.get()可以返回一个null <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)--执行提交的Callable集合,然后返回各自的执行结果的Future对象列表,每个元素isDone都是true
throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)--执行提交的task集合,执行完成或者timeout之后返回结果,isDone为true
throws InterruptedException; <T> T invokeAny(Collection<? extends Callable<T>> tasks)--执行提交的task集合,有一个执行完成就返回结果
throws InterruptedException, ExecutionException; <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)--同上,有一个执行完成或者有timeout出现
throws InterruptedException, ExecutionException, TimeoutException;

 AbstractExecutorService实现了ExecutorService接口,并且声明为抽象类,然而其中一个抽象方法都没有。。.


public abstract class AbstractExecutorService implements ExecutorService {
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {---为子类定义了一个创建RunnableFuture对象的快捷方法
return new FutureTask<T>(runnable, value);
}
---其余方法都是接口的实现方法 }

 还有一个继承了ExecutorService的接口的接口:


public interface ScheduledExecutorService extends ExecutorService { ---定义延迟执行的动作
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit); ---延迟delay个时间单位后开始执行 public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);---延迟delay个时间单位后执行并返回Future对象 public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);在initialDelay、initialDelay+N*period分别出发
  public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                              long initialDelay,
                               long delay,
                              TimeUnit unit); }--initialDelay开始进行,后面每次执行成功后的dealy时间单位开始

接下来是重磅的内容ThreadPoolExecutor 也就是Executor框架的核心逻辑所在,ThreadPoolExecutor类算上注释有2100多行,但里面有很多一部分是方法的详细说明,还有大量的变量和private/protected的方法,真正开放出来的public方法很少,我们只要逐个分析这些public方法就可以了。

我们首先来看构造函数,构造函数有多个重载方法,目前只看参数最全的情况:

public ThreadPoolExecutor(int corePoolSize, ----池子里面的线程数量,即便idle状态的线程也会保留这个数量
int maximumPoolSize,----池子里面能盛放最大线程数量
long keepAliveTime,----当线程数量大于core核心数量的时候,并且里有idle状态的线程,那么最大可以被terminate的的等待时间
                                 (就是在cpu借的线程资源如果闲置多久就必须还回去)
TimeUnit unit,--timeUnit
BlockingQueue<Runnable> workQueue,---任务的队列
ThreadFactory threadFactory,---线程工厂
RejectedExecutionHandler handler) {---线程池处理不过来任务队列的时候的默认处理方法
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
public void execute(Runnable command) {}---执行一个任务
public void shutdown() {---使用可重入锁实现,关闭线程池执行框架,不再接受新的任务,关闭idle状态的线程,等待正在执行的执行完成。
final ReentrantLock mainLock = this.mainLock;
}
public List<Runnable> shutdownNow() {}--- 同ExecutorService中的接口说明,与shuwdown的区别在于会尝试关闭正在执行的线程

public boolean isShutdown() {}---是否已经关闭(没有running状态的线程了)

-------一堆get和set方法
public int getActiveCount() {}---获得活动的线程数量
public long getCompletedTaskCount() {}---或者完成的任务数量

其实我们只要知道ThreadPoolExecutor的构造参数就可以明白它的工作方式,而且我们需要做的也是把这些内容构造好。

我们最常用的Executors里面的更加方便的Pool的类型其实都是为我们加了一些default参数的ThreadPoolExecutor:

public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1, threadFactory));
}
也就是其实最后都是会到ThreadPoolExecutor上面去实现,区别就是一个用着方便,一个你可以控制的粒度更小,进而可能效率更高。

我们在类图的继承体系里面还能发现一个叫做ForkJoinPool的类,这个类其实是很多人口中所谓未来java并发方向的类,由于涉及的内容较多,后面单独随笔进行学习和理解吧。

 

java.util.concurrent包学习笔记(一)Executor框架的更多相关文章

  1. Java.util.concurrent包学习(一) BlockingQueue接口

    JDK1.7 BlockingQueue<E>接口 (extends Queue<E>) 所有父接口:Collection<E>,Iterable<E> ...

  2. java.util.concurrent包API学习笔记

    newFixedThreadPool 创建一个固定大小的线程池. shutdown():用于关闭启动线程,如果不调用该语句,jvm不会关闭. awaitTermination():用于等待子线程结束, ...

  3. java Concurrent包学习笔记(一):ExecutorService

    一.介绍 ExecutorService是java.util.concurrent包中的一个线程池实现接口.其有两个实现类: 1)ThreadPoolExecutor:普通线程池通过配置线程池大小,能 ...

  4. 【并发编程】【JDK源码】JDK的(J.U.C)java.util.concurrent包结构

    本文从JDK源码包中截取出concurrent包的所有类,对该包整体结构进行一个概述. 在JDK1.5之前,Java中要进行并发编程时,通常需要由程序员独立完成代码实现.当然也有一些开源的框架提供了这 ...

  5. java.util.concurrent包

    在JavaSE5中,JUC(java.util.concurrent)包出现了 在java.util.concurrent包及其子包中,有了很多好玩的新东西: 1.执行器的概念和线程池的实现.Exec ...

  6. 《java.util.concurrent 包源码阅读》 结束语

    <java.util.concurrent 包源码阅读>系列文章已经全部写完了.开始的几篇文章是根据自己的读书笔记整理出来的(当时只阅读了部分的源代码),后面的大部分都是一边读源代码,一边 ...

  7. 线程并发线程安全介绍及java.util.concurrent包下类介绍

    线程Thread,在Java开发中多线程是必不可少的,但是真正能用好的并不多! 首先开启一个线程三种方式 ①new Thread(Runnable).start() ②thread.start(); ...

  8. The java.util.concurrent Synchronizer Framework笔记

    这篇笔记是关于 Doug Lea 的 The java.util.concurrent Synchronizer Framework . 原文地址:http://gee.cs.oswego.edu/d ...

  9. 深入理解java:2.3. 并发编程 java.util.concurrent包

    JUC java.util.concurrent包, 这个包是从JDK1.5开始引入的,在此之前,这个包独立存在着,它是由Doug Lea开发的,名字叫backport-util-concurrent ...

随机推荐

  1. [javaEE] web应用的目录结构&配置虚拟主机

    myWebSite | |-- 静态资源和JSP文件都可以直接放在web应用目录下,浏览器可以直接访问 |-- WEB-INF 浏览器没有办法直接访问 |-- classes 动态web运行时的cla ...

  2. mybatis_02简单操作数据库

    模糊查询用户信息 <!-- [${}]:表示拼接SQL字符串 [${value}]:表示要拼接的是简单类型参数. 注意: 1.如果参数为简单类型时,${}里面的参数名称必须为value 2.${ ...

  3. springMVC_05结果跳转方式

    一.总结 总共有四个, 1.设置ModelAndView的值,根据view和视图解析器跳转到指定的页面 2.通过servletapi对象来实现,不需要视图解析器 3.通过springmvc来实现转发和 ...

  4. 初识 Java-监听器

    使用Listener类当java  web应用程序在web容器中运行时,在java web应用程序内部会不断发生各种事件,例如web应用的启动,暂停,销毁等.以及web应用中session开始和结束 ...

  5. Vue2+VueRouter2+webpack 构建项目实战(五):配置子路由

    前言 通过前面几章的实战,我们已经顺利的构建项目,并且从API接口获取到数据并且渲染出来了.制作更多的页面,更复杂的应用,就是各位自己根据自己的项目去调整的事情了. 本章讲一下如何配置子路由,因为我们 ...

  6. 一次断电引发的svn数据库故障

    作者:朱金灿 来源:http://blog.csdn.net/clever101 昨天办公室停电了.然后今天更新svn数据库时出现一个不能读取文件:End of file found的错误,具体如下图 ...

  7. OneAPM 获得“2018中国 IT 服务创新奖”,彰显技术创新实力

    6月30日,主题为“智能服务 数字中国”的中国 IT 服务创新大会在京召开.作为第22届中国国际软件博览会的重头戏,本次大会由工业和信息化部.北京市人民政府共同主办,中国电子工业标准化技术协会信息技术 ...

  8. mssql sqlserver 从指定字符串中获取数字的方法

    转自:http://www.maomao365.com/?p=6410 摘要: 下文主要分享从指定字符串或列中获取数字信息,如下所示: 实验环境:sql server 2000 ----编写sql函数 ...

  9. tesseract安装及问题处理

    错误1 pytesseract.pytesseract.TesseractNotFoundError: tesseract is not installed or it's not in your p ...

  10. SQL Server 锁实验(UPDATE加锁探究)

    update语句: 本例中由于看到的是update执行完的锁情况,因此无法看到IU锁,但其实针对要修改的数据页和索引页会先加IU锁,记录和键先加U锁,然后再转化为IX和X锁. 如果想要看到IU锁和U锁 ...