热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

理解java多线程中ExecutorService使用

这篇文章主要帮助大家理解java多线程中ExcetorServiced的使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

java.util.concurrent包里提供了关于多线程操作的类,平常用的比较多的是ExecutorService及其实现类(如ThreadPoolExecutor等),Executor,Executors,Future,Callable等

1. ExecutorService(继承自Executor)接口:提供了一些异步的多线程操作方法,如execute(), submit(), shutdown(), shutdownNow()等

2. Executor接口:执行提交的任务(线程),只有一个方法 execute(Runnable a)

2. Executors类: 提供了一些工厂方法和一些公共方法来操作Executor子类和ThreadFactory等,如newXXX(),xxxThreadFactory()等

3. Futrue接口:代表了线程执行结果,提供了获取线程执行结果和取消线程的方法,如get(),cancle()等

4. Callable接口:JDK1.5提供的有返回值的线程执行新接口

对ExecutorService和Future的理解做简单记录

代码:

public class Main {
  private static int count = 0;

  public static void main(String[] args){
    List resultList = new LinkedList<>();

    /**
     * Executors.newCachedThreadPool() 创建一个线程缓存池,若60s中线程没有被使用,则会停止线程并从缓存池中移除
     * Executors.newScheduledThreadPool() 创建一个固定容量的线程池,里边的线程按照设定的调度时间执行
     * Executors.newFixedThreadPool()  拥有固定容量的线程缓存池
     * Executors.newSingleThreadExecutor() 容量为一的线程缓存池,只会有一个线程
     */
    ExecutorService executorService = Executors.newCachedThreadPool();
    for(int i=0; i<10; i++){
      Future future = executorService.submit(new Callable() {
        @Override
        public String call() {
          try {
            System.out.println(Thread.currentThread().getName());
            Thread.sleep(5000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          int count = Main.count;
          System.out.println(Thread.currentThread().getName() + "..start Main count:..." + count);
          Main.count = ++count;
          System.out.println(Thread.currentThread().getName() + "..end Main count:..." + Main.count);
          return Thread.currentThread().getName();
        }
      });
      resultList.add(future);
    }
    executorService.shutdown();
    for(Future future: resultList){
      try {
        System.out.println(future.get() + "..is over...");
      } catch (InterruptedException e) {
        e.printStackTrace();
      } catch (ExecutionException e) {
        e.printStackTrace();
      }
    }
    System.out.println("main thread end...");
  }
}

输出:

pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
pool-1-thread-6
pool-1-thread-7
pool-1-thread-8
pool-1-thread-9
pool-1-thread-10
pool-1-thread-1..start Main count:...0
pool-1-thread-2..start Main count:...0
pool-1-thread-3..start Main count:...1
pool-1-thread-2..end Main count:...1
pool-1-thread-1..end Main count:...1
pool-1-thread-3..end Main count:...2
pool-1-thread-1..is over...
pool-1-thread-2..is over...
pool-1-thread-4..start Main count:...2
pool-1-thread-3..is over...
pool-1-thread-4..end Main count:...3
pool-1-thread-4..is over...
pool-1-thread-5..start Main count:...3
pool-1-thread-5..end Main count:...4
pool-1-thread-5..is over...
pool-1-thread-6..start Main count:...4
pool-1-thread-6..end Main count:...5
pool-1-thread-6..is over...
pool-1-thread-7..start Main count:...5
pool-1-thread-7..end Main count:...6
pool-1-thread-7..is over...
pool-1-thread-8..start Main count:...6
pool-1-thread-8..end Main count:...7
pool-1-thread-8..is over...
pool-1-thread-9..start Main count:...7
pool-1-thread-9..end Main count:...8
pool-1-thread-9..is over...
pool-1-thread-10..start Main count:...8
pool-1-thread-10..end Main count:...9
pool-1-thread-10..is over...
main thread end... //主线程在所有线程执行完成后结束

控制台在等待5秒后打印出上边的输出结果,原因是所有的线程启动的时候是一个并发操作,都会去等待5秒,所以整体看来只等了5秒,这是一个并发操作

总结:

1. ExecutorService提供的execute()方法和submit()方法的区别:

  a. execute()方法只接受Runnable类型的实例,所以不能拿到返回值,也不能动态获取线程执行的情况

  b. submit()方法接受Runnable和Callable实例,会返回Future实例,Future实例的get()方法可以获取线程执行返回值,并能抛出线程执行异常。所以如果要获取线程执行返回的结果,并能处理线程执行时可能出现的异常,或者想中途取消线程执行时可以使用submit()方法

2. 通过输出可以看到main方法(主线程)在所有线程执行完成后结束,原因:

  a. 通过submit()方法获取Future实例,并通过Future实例的get()方法获取线程返回结果,而Future实例的get()方法会等待线程执行完毕才会返回,所以main方法会等待所有子线程结束才会结束

  b. 若去掉上边红色标注的for循环,则main方法(主线程)会提前结束,而不会等待所有子线程结束

补充:

1. 多个线程并发执行时,若其中某一个线程出现了异常并且没有被处理,则该线程会自动停止执行,但其他线程还是会正常执行,这就是为什么tomcat请求出现异常时,tomcat还可以继续提供服务的原因。

2. tomcat提供了线程池和等待池,每一个请求过来都会重新启动一个新的线程处理该请求,若线程池中线程用完,再来请求的时候就会放到等待池中等待,当其中有线程释放回线程池中时,就会为等待池中的请求分配线程处理请求。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 显卡驱动对游戏的影响及其提升效果的研究
    本文研究了显卡驱动对游戏体验的提升效果,通过比较新旧驱动加持下的RTX 2080Ti显卡在游戏体验上的差异。测试平台选择了i9-9900K处理器和索泰RTX 2080Ti玩家力量至尊显卡,以保证数据的准确性。研究结果表明,显卡驱动的更新确实能够带来近乎50%的性能提升,对于提升游戏体验具有重要意义。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 本文介绍了关于apache、phpmyadmin、mysql、php、emacs、path等知识点,以及如何搭建php环境。文章提供了详细的安装步骤和所需软件列表,希望能帮助读者解决与LAMP相关的技术问题。 ... [详细]
  • PHPMailer邮件类邮件发送功能的使用教学及注意事项
    本文介绍了使用国外开源码PHPMailer邮件类实现邮件发送功能的简单教学,同时提供了一些注意事项。文章涵盖了字符集设置、发送HTML格式邮件、群发邮件以及避免类的重定义等方面的内容。此外,还提供了一些与PHP相关的资源和服务,如传奇手游游戏源码下载、vscode字体调整、数据恢复、Ubuntu实验环境搭建、北京爬虫市场、进阶PHP和SEO人员需注意的内容。 ... [详细]
  • 标题: ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文总结了淘淘商城项目的功能和架构,并介绍了传统架构中遇到的session共享问题及解决方法。淘淘商城是一个综合性的B2C平台,类似京东商城、天猫商城,会员可以在商城浏览商品、下订单,管理员、运营可以在平台后台管理系统中管理商品、订单、会员等。商城的架构包括后台管理系统、前台系统、会员系统、订单系统、搜索系统和单点登录系统。在传统架构中,可以采用tomcat集群解决并发量高的问题,但由于session共享的限制,集群数量有限。本文探讨了如何解决session共享的问题。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • MySQL语句大全:创建、授权、查询、修改等【MySQL】的使用方法详解
    本文详细介绍了MySQL语句的使用方法,包括创建用户、授权、查询、修改等操作。通过连接MySQL数据库,可以使用命令创建用户,并指定该用户在哪个主机上可以登录。同时,还可以设置用户的登录密码。通过本文,您可以全面了解MySQL语句的使用方法。 ... [详细]
  • 分享css中提升优先级属性!important的用法总结
    web前端|css教程css!importantweb前端-css教程本文分享css中提升优先级属性!important的用法总结微信门店展示源码,vscode如何管理站点,ubu ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
author-avatar
u44093631
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有