当前位置: 首页 > 编程日记 > 正文

ExecutorService与Executors例子的简单剖析(转)

对于多线程有了一点了解之后,那么来看看java.lang.concurrent包下面的一些东西。在此之前,我们运行一个线程都是显式调用了 Thread的start()方法。我们用concurrent下面的类来实现一下线程的运行,而且这将成为以后常用的方法或者实现思路。 

        看一个简单的例子:

Java代码  收藏代码
  1. public class CacheThreadPool {
  2. public static void main(String[] args) {
  3. ExecutorService exec=Executors.newCachedThreadPool();
  4. for(int i=0;i<5;i++)
  5. exec.execute(new LiftOff());
  6. exec.shutdown();//并不是终止线程的运行,而是禁止在这个Executor中添加新的任务
  7. }
  8. }


        这个例子其实很容易看懂,ExecutorService中有一个execute方法,这个方法的参数是Runnable类型。也就是说,将一个实现了Runnable类型的类的实例作为参数传入execute方法并执行,那么线程就相应的执行了。 

        一、ExecutorService 
        先看看ExecutorService,这是一个接口,简单的列一下这个接口:

Java代码  收藏代码
  1. public interface ExecutorService extends Executor {
  2. void shutdown();
  3. List<Runnable> shutdownNow();
  4. boolean isShutdown();
  5. boolean isTerminated();
  6. boolean awaitTermination(long timeout, TimeUnit unit)
  7. <T> Future<T> submit(Callable<T> task);
  8. <T> Future<T> submit(Runnable task, T result);
  9. Future<?> submit(Runnable task);
  10. <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
  11. <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
  12. <T> T invokeAny(Collection<? extends Callable<T>> tasks)
  13. <T> T invokeAny(Collection<? extends Callable<T>> tasks,
  14. long timeout, TimeUnit unit)
  15. }


        ExecuteService继承了Executor,Executor也是一个接口,里面只有一个方法:

Java代码  收藏代码
  1. void execute(Runnable command)



        二、Executors 
        Executors是一个类,直接援引JDK文档的说明来说一下这个类的作用: 

    • Factory and utility methods for Executor, ExecutorService, ScheduledExecutorService, ThreadFactory, and Callable classes defined in this package. This class supports the following kinds of methods:

  • Methods that create and return an ExecutorService set up with commonly useful configuration settings.
  • Methods that create and return a ScheduledExecutorService set up with commonly useful configuration settings.
  • Methods that create and return a "wrapped" ExecutorService, that disables reconfiguration by making implementation-specific methods inaccessible.
  • Methods that create and return a ThreadFactory that sets newly created threads to a known state.
  • Methods that create and return a Callable out of other closure-like forms, so they can be used in execution methods requiring Callable.


        在上面的例子中,我们用到了newCachedThreadPool()方法。看一下这个方法:

Java代码  收藏代码
  1. public static ExecutorService newCachedThreadPool() {
  2. return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
  3. 60L, TimeUnit.SECONDS,
  4. new SynchronousQueue<Runnable>());
  5. }


        在源码中我们可以知道两点,1、这个方法返回类型是ExecutorService;2、此方法返回值实际是另一个类的实例。看一下这个类的信息:

Java代码  收藏代码
  1. public class ThreadPoolExecutor extends AbstractExecutorService {
  2. ..........
  3. private final BlockingQueue<Runnable> workQueue;//这个变量在下面会提到
  4. ..........
  5. }


        ThreadPoolExecutor继承了AbstractExecutorService,而AbstractExecutorService又实现 了ExecutorService接口。所以,根据多态,ThreadPoolExecutor可以看作是ExecutorService类型。 

        线程执行的最关键的一步是执行了executor方法,根据java的动态绑定,实际执行的是ThreadPoolExecutor所实现的executor方法。看看源码:

Java代码  收藏代码
  1. public class ThreadPoolExecutor extends AbstractExecutorService {
  2. ..........
  3. public void execute(Runnable command) {
  4. if (command == null)
  5. throw new NullPointerException();
  6. if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
  7. if (runState == RUNNING && workQueue.offer(command)) {
  8. if (runState != RUNNING || poolSize == 0)
  9. ensureQueuedTaskHandled(command);
  10. }
  11. else if (!addIfUnderMaximumPoolSize(command))
  12. reject(command); // is shutdown or saturated
  13. }
  14. }
  15. ..........
  16. }


        根据程序正常执行的路线来看,这个方法中比较重要的两个地方分别是: 
        1、workQueue.offer(command) 
        workQueue在上面提到过,是BlockingQueue<Runnable>类型的变量,这条语句就是将Runnable类型的实例加入到队列中。 
        2、ensureQueuedTaskHandled(command) 
        这个是线程执行的关键语句。看看它的源码:

Java代码  收藏代码
  1. public class ThreadPoolExecutor extends AbstractExecutorService {
  2. ..........
  3. private void ensureQueuedTaskHandled(Runnable command) {
  4. final ReentrantLock mainLock = this.mainLock;
  5. mainLock.lock();
  6. boolean reject = false;
  7. Thread t = null;
  8. try {
  9. int state = runState;
  10. if (state != RUNNING && workQueue.remove(command))
  11. reject = true;
  12. else if (state < STOP &&
  13. poolSize < Math.max(corePoolSize, 1) &&
  14. !workQueue.isEmpty())
  15. t = addThread(null);
  16. finally {
  17. mainLock.unlock();
  18. }
  19. if (reject)
  20. reject(command);
  21. else if (t != null)
  22. t.start();
  23. }
  24. ..........
  25. }


        在这里我们就可以看到最终执行了t.start()方法来运行线程。在这之前的重点是t=addThread(null)方法,看看addThread方法的源码:

Java代码  收藏代码
  1. public class ThreadPoolExecutor extends AbstractExecutorService {
  2. ..........
  3. private Thread addThread(Runnable firstTask) {
  4. Worker w = new Worker(firstTask);
  5. Thread t = threadFactory.newThread(w);
  6. if (t != null) {
  7. w.thread = t;
  8. workers.add(w);
  9. int nt = ++poolSize;
  10. if (nt > largestPoolSize)
  11. largestPoolSize = nt;
  12. }
  13. return t;
  14. }
  15. ..........
  16. }


        这里两个重点,很明显: 
        1、Worker w = new Worker(firstTask) 
        2、Thread t = threadFactory.newThread(w) 
        先看Worker是个什么结构:

Java代码  收藏代码
  1. public class ThreadPoolExecutor extends AbstractExecutorService {
  2. ..........
  3. private final class Worker implements Runnable {
  4. ..........
  5. Worker(Runnable firstTask) {
  6. this.firstTask = firstTask;
  7. }
  8. private Runnable firstTask;
  9. ..........
  10. public void run() {
  11. try {
  12. Runnable task = firstTask;
  13. firstTask = null;
  14. while (task != null || (task = getTask()) != null) {
  15. runTask(task);
  16. task = null;
  17. }
  18. finally {
  19. workerDone(this);
  20. }
  21. }
  22. }
  23. Runnable getTask() {
  24. for (;;) {
  25. try {
  26. int state = runState;
  27. if (state > SHUTDOWN)
  28. return null;
  29. Runnable r;
  30. if (state == SHUTDOWN)  // Help drain queue
  31. r = workQueue.poll();
  32. else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
  33. r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
  34. else
  35. r = workQueue.take();
  36. if (r != null)
  37. return r;
  38. if (workerCanExit()) {
  39. if (runState >= SHUTDOWN) // Wake up others
  40. interruptIdleWorkers();
  41. return null;
  42. }
  43. // Else retry
  44. catch (InterruptedException ie) {
  45. // On interruption, re-check runState
  46. }
  47. }
  48. }
  49. }
  50. ..........
  51. }


        Worker是一个内部类。根据之前可以知道,传入addThread的参数是null,也就是说Work中firstTask为null。
        在看看newThread是一个什么方法:

Java代码  收藏代码
  1. public class Executors {
  2. ..........
  3. static class DefaultThreadFactory implements ThreadFactory {
  4. ..........
  5. public Thread newThread(Runnable r) {
  6. Thread t = new Thread(group, r,
  7. namePrefix + threadNumber.getAndIncrement(),
  8. 0);
  9. if (t.isDaemon())
  10. t.setDaemon(false);
  11. if (t.getPriority() != Thread.NORM_PRIORITY)
  12. t.setPriority(Thread.NORM_PRIORITY);
  13. return t;
  14. }
  15. ..........
  16. }
  17. ..........
  18. }


        通过源码可以得知threadFactory的实际类型是DefaultThreadFactory,而DefaultThreadFactory是Executors的一个嵌套内部类。 

        之前我们提到了t.start()这个方法执行了线程。那么现在从头顺一下,看看到底是执行了谁的run方法。首先知 道,t=addThread(null),而addThread内部执行了下面三步,Worker w = new Worker(null);Thread t = threadFactory.newThread(w);return t;这里两个t是一致的。 
        从这里可以看出,t.start()实际上执行的是Worker内部的run方法。run()内部会在if条件里面使用“短路”:判断firstTask 是否为null,若不是null则直接执行firstTask的run方法;如果是null,则调用getTask()方法来获取Runnable类型实 例。从哪里获取呢?workQueue!在execute方法中,执行ensureQueuedTaskHandled(command)之前就已经把 Runnable类型实例放入到workQueue中了,所以这里可以从workQueue中获取到。

相关文章:

GridView隐藏列取值解决方案

【摘要】 在Asp.net 2.0中增加了一个新的数据绑定控件&#xff1a;GridView&#xff0c;其目的用来取代Asp.net1.x中的DataGrid控件&#xff0c;但有一点很不爽的是&#xff0c;如果把某列设置为visiblefalse&#xff0c;则不会进行数据绑定&#xff0c;也就是说无法直接从Grid…

百度飞桨成为北京市首个AI产业方向创新应用平台

1月20日&#xff0c;北京市经济和信息化局正式授予百度公司"北京市人工智能产业创新应用平台&#xff08;百度飞桨&#xff09;"。当前&#xff0c;北京市正在创建国家人工智能创新应用先导区&#xff0c;人工智能作为新科技革命和产业变革前沿领域&#xff0c;是北京…

FTP的20、21端口,工作模式

什么是FTP? FTP就是文件传输协议 File Transfer Protocol 的缩写. FTP端口号是多少? 21 FTP的端口号能改吗? 能 ftp的端口号20、21有何区别? 一个是数据端口&#xff0c;一个是控制端口&#xff0c;控制端口一般为21&#xff0c;而数据端口不一定是20&#xff0c;这和FTP的…

android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu[转]

http://blog.csdn.net/jj120522/article/details/8095852 示意图就不展示了&#xff0c;和上一节的一样,滑动菜单SlidingMenu效果如何大家都比较熟悉&#xff0c;在这里我简单说明一下用自定义ViewGroup来实现. 实现方法&#xff1a;我们自定义一个ViewGroup实现左右滑动&#…

物联网下的数据传输,Python 就能搞定!

作者 | 李秋键责编 | 夕颜出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;引言&#xff1a;近几年来&#xff0c;谈起发展最火热的几个关键词必然是人工智能、大数据以及物联网的万物互联、边缘计算等等了。而今天&#xff0c;我们就将利用Python实现物联网下的数据传…

ASP.NET 2.0中Page事件的执行顺序

Page 执行中将按照如下顺序激活事件&#xff1a;Page.PreInitPage.InitPage.InitComplitePage.PreLoadPage.LoadPage.LoadCompletePage.PreRenderPage.PreRenderComplete如果页面从令一个页面继承&#xff0c;如BasePage:System.Web.UI.Page&#xff0c;在BasePage中做了一些扩…

javascript函数嵌套时arguments的问题

疑问&#xff1a; var funtest function () {var fun function (val, val2) {alert(arguments.length); //此处答案&#xff1f; 有些人回答是2&#xff0c;但是正确是 0 };setTimeout(fun, 20);};funtest(); 转载于:https://www.cnblogs.com/huaan011/p/7073792.html

禁用页面缓存的几种方法(静态和动态)

1、在Asp页面首部<head>加入 Response.Buffer True Response.ExpiresAbsolute Now() - 1 Response.Expires 0 Response.CacheControl "no-cache" Response.AddHeader "Pragma", "No-Cache&…

程序员转型AI,成功几率有几分?

技术转型&#xff0c;这两年一直是程序员圈子里的热门话题。对于大部分基层程序员来说&#xff0c;基础岗位上薪资的涨幅很难跟上年龄的增长。而近些年&#xff0c;AI技术发展势头迅猛&#xff0c;优秀人才短缺&#xff0c;这种情况下&#xff0c;无疑是谁先转型&#xff0c;谁…

利用反射实现类的动态加载

为什么80%的码农都做不了架构师&#xff1f;>>> //首先定义一个接口来隔离类&#xff1a; public interface Operator { // public java.util.List act(java.util.List params);public java.util.List act(String content,String content2,java.util.List param…

spring+ (activeMQ) 实现queue与topic

2019独角兽企业重金招聘Python工程师标准>>> 2017-06-17 1、activeMQ下载与安装 前往Apache官网下载ActiveMQ&#xff0c;下载地址http://activemq.apache.org/download.html&#xff08;此处我下载了apache-activemq-5.9.0 版本的tar包&#xff09;解压&#xff1a…

C#文本文件操作

如何向现有文件中添加文本using System;using System.IO;class Test {public static void Main() {// Create an instance of StreamWriter to write text to a file.// The using statement also closes the StreamWriter.using (StreamWriter sw new StreamWriter("Tes…

RISC-V 正在成为芯片世界中的 Linux

【编者按】芯片推动了人类社会数字化、信息化、智能化的发展。从某种程度上来说&#xff0c;芯片技术的发展也影响着行业未来的走向。你觉得未来的芯片世界将会如何&#xff1f;编译 | 虎说八道 责编 | 张文头图 | CSDN 下载自视觉中国出品 | CSDN&#xff08;ID&#xff1a;C…

linux系统小记

1.当某分区空间剩余很大时&#xff0c;可用dd命令写入0&#xff0c;做成很大的文件后格式化&#xff0c;可当作分区使用&#xff08;-o loop挂载&#xff09;#dd if/dev/zero of/wq bs1M count512#mkfs -t ext3 /wq#mkswap /wq#swapon /wq#mount -o loop /wq /data#mou…

网络编程 -- RPC实现原理 -- RPC -- 迭代版本V3 -- 远程方法调用 整合 Spring

网络编程 -- RPC实现原理 -- 目录 啦啦啦 V3——RPC -- 远程方法调用 及 null的传输 Spring 服务提供商&#xff1a; 1. 配置 rpc03_server.xml 注入 服务提供商 rpcServiceProvider并指定初始化方法 及 服务实例 IUserService 2. 读取 服务消费者 请求的 MethodStaics &…

Rootkit之SSDT hook(通过CR0)

SSDT即System Service Dispath Table&#xff0c;它是一个表&#xff0c;这个表中有内核调用的函数地址。KeServiceDescriptorTable&#xff1a;是由内核&#xff08;Ntoskrnl.exe&#xff09;导出的一个表&#xff0c;这个表是访问SSDT的关键&#xff0c;具体结构是typedef st…

禁止validateRequest的办法

A potentially dangerous Request.Form value was detected from the client (txtTest"<b>"). 由于在.net中&#xff0c;Request时出现有HTML或Javascript等字符串时&#xff0c;系统会认为是危险性值。立马报错。 解决方案一&#xff1a; 在.a…

多画面、实时投票,这场上了一晚热搜的超级晚,背后的技术出圈了

"让观众当导演&#xff0c;自己决定演出顺序&#xff1f;" "不仅直播前台演出&#xff0c;还可以看到候场区明星吃火锅&#xff1f;" 你没听错&#xff0c;在各种直播、晚会频出的岁末年初&#xff0c;最近有一台超级晚出圈了。 1月15日&#xff0c;2021爱…

linux下挂载硬盘

2019独角兽企业重金招聘Python工程师标准>>> 切换到root用户 su - root 查看硬盘信息 fdisk -l Disk /dev/sda: 42.9 GB, 42949672960 bytes 255 heads, 63 sectors/track, 5221 cylinders Units cylinders of 16065 * 512 8225280 bytes Sector size (logical/ph…

通过创建 HttpCookie 对象的实例编写 Cookie

通过创建 HttpCookie 对象的实例编写 Cookie HttpCookie myCookie new HttpCookie("UserSettings");myCookie["Font"] "Arial";myCookie["Color"] "Blue";myCookie.Expires DateTime.Now.AddDays(1d);Response.Cookies…

亚马逊云服务(AWS)云原生自研处理器首次落地中国区域!

2021年1月28日&#xff0c;亚马逊云服务&#xff08;AWS&#xff09;正式宣布&#xff0c;由 AWS Graviton2 处理器提供支持的 Amazon Elastic Compute Cloud &#xff08;Amazon EC2&#xff09; M6g、C6g 和 R6g 实例已在由光环新网运营的 AWS 中国&#xff08;北京&#xff…

一个古老的问题HashMap与Hashtable区别

HashTable的应用非常广泛&#xff0c;HashMap是新框架中用来代替HashTable的类&#xff0c;也就是说建议使用HashMap&#xff0c;不要使用HashTable。可能你觉得HashTable很好用&#xff0c;为什么不用呢&#xff1f;这里简单分析他们的区别。 1.HashTable的方法是同步的&#…

如何修改可运行Jar包,如何反编译Jar包

将可运行Jar包&#xff0c;反编译成项目&#xff0c;修改代码&#xff0c;再次编译&#xff0c;打包。 需要工具&#xff1a;jd-gui、myeclipse 具体步骤&#xff1a; 1、使用jd-gui打开原始的Jar包&#xff0c;选择File-->Save All Sources&#xff0c;会生成一个zip压缩包…

告别手敲 SQL ?GPT-3 自动帮你写

作者 | Brian Kane SeekWell 编译 | 伍杏玲 出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 【导语】手写业务 SQL 很繁琐&#xff1f;GPT-3来帮你&#xff01;本文作者通过手动输入简单的英文描述秒 Get 到 SQL 了。听说 AI 又来抢开发者饭碗&#xff0…

Java IO 体系结构

参考文章地址: http://blog.csdn.net/oracle_microsoft/article/details/2634231 Java IO体系结构看似庞大复杂,其实有规律可循,要弄清楚其结构,需要明白两点: 1. 其对称性质:InputStream 与 OutputStream, Reader 与 Writer,他们分别是一套字节输入-输出,字符输入-输出体系 2.…

ACCESS数据库防止下载

1. 修改数据库名。这是常用方法&#xff0c;将数据库名该成怪异名字或长名字&#xff0c;以防别人猜测。一旦被人猜到&#xff0c;别人还是能下载数据库文件&#xff0c;但几率不大。如将数据库database.mdb改成dslfjds$^&ijjkgf.mdb等 2. 修改数据库后缀。一般改成databa…

CentOS 7 SSH 免密登录的方法

先决条件 3 台 CentOS 7 HOSTNAMEIPROLEserver110.8.26.197Masterserver210.8.26.196Slave1server310.8.26.195Slave21. 用 root 用户登录。每台服务器都生成公钥&#xff0c;再合并到 authorized_keys。 2. CentOS 默认没有启动 ssh 无密登录&#xff0c;去掉 /etc/ssh/sshd_c…

webconfig加密

退到根目录 cd/跳到某盘 c: ..跳到某目录 cd Documents and Settings/All Users上一层 cd .. cd WINDOWS/Microsoft.NET/Framework/v2.0.50727 回车 aspnet_regiis -pef connectionStrings D:/NET aspnet_regiis -pe connectionStrings -app /NET 虚拟目录aspnet_regiis -pd…

WIN7 任务栏放右侧 有个BUG

不能变窄啊&#xff0c;微软又在设计上。转载于:https://www.cnblogs.com/whitetiger/p/3269827.html

全领域通吃,12个经典Python数据可视化库盘点

责编 | 寇雪芹头图 | 下载于视觉中国来源 | 博文视点BroadviewPython有很多数据可视化库&#xff0c;这些数据可视化库主要分为探索式可视化库和交互式可视化库。前者透过简单直接的视觉图形&#xff0c;更方便用户看懂原数据&#xff0c;后者主要用于与业务结合过程中展现总体…