zoukankan      html  css  js  c++  java
  • Java多线程——<三>简单的线程执行:Executor

    一、概述

      按照《Java多线程——<一><二>》中所讲,我们要使用线程,目前都是显示的声明Thread,并调用其start()方法。多线程并行,明显我们需要声明多个线程然后都调用他的start方法,这么一看,似乎有些问题:第一、线程一旦多了,声明势必是个问题;第二、多线程启动如果通过手动执行的话,那可能一个线程已经跑完了,另外一个还没起来(我推测可能会出现这个问题)。所以,我们在想,如果有个管家,能够帮我们管理这么多线程,只需要把我们定义的任务交给管家,管家就能够帮我们把任务附着到线程上,并且当我们给管家发送指令让所有的线程开始并发执行时,他也能够帮助我们开启所有线程执行。

    二、java多线程管家——Executor

      Executor允许你管理异步任务的执行,而无须显示地管理线程的生命周期。ExecutorService知道如何构建恰当的上下文来执行Runnable对象。
      1.创建ExecutorService 

      通过Executors能够创建两种方式的ExectorService。第一种、CachedThreadPool会为每个传入的任务新创建一个线程

      ExecutorService exec = Executors.newCachedThreadPool();

      第二种、FixedThreadPool可以一次性预先执行代价高昂的线程分配,所以可以用来限制线程的数量。这可以节省时间,因为你不必为每个任务都固定的付出创建线程的开销。

      ExecutorService exeService = Executors.newFixedThreadPool(5);

      2.把任务附着给ExecutorService

      有了executor,你只需要定义任务并将任务对象传递给executor即可。

      exeService.execute(new Task());

      3.让所有任务开始执行

      这两个方法会让之前提交到该exectuor的所有任务开始执行。为了避免启动后,会被注入新的任务,必须在你将所有线程注入后,执行关闭操作以保证这一点。

      exeService.shutdown();

    总结:

        |——原来:想执行任务
        |            |            |——1.定义任务
        |            |            |——2.创建任务对象交由Thread对象操纵
        |            |            |——3.显示的调用Thread对象的start()方法
        |            |——遇到问题:比较繁琐,总得自己启动线程调用;本质上是由main函数调用的
        |——现在:使用java.util.concurrent.Executor(执行器)来管理Thread对象
        |            |            |——1.ExecutorService exec = Executors.newAcahedThreadPool();
        |            |            |——2.exec.execute(new Task());
        |            |            |——3.exec.shutdown();
        |            |——在客户端(显示调用线程执行)和执行任务之间提供了一个间接层,用以执行任务;撇开了main函数,由executor直接进行了调用
        |            |——允许你管理异步任务的执行,而无须显示地管理线程的生命周期

    三、其他

    1.何时使用哪种线程池呢?
      CachedThreadPool在程序执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程,因此它是合理的Executor的首选
      只有当这种方式会引起问题时,才需要切换到FixedThreadPool。

    2.SingleThreadExecutor

    SingleThreadExecutor就像是线程数量为1的FixedThreadPool
           |——在另一个线程中连续运行的任何事务来说都很有用(重点是连续运行,因为这样可以顺序接受处理),故SingleThreadPool会序列化所有提交给它的任务,       并会维护它自己隐藏的悬挂任务队列
           |——例如:向SingleThreadExecutor提交多个任务,那么这些任务将排队,每个任务都会在下一个任务开始之前运行结束,所有任务使用相同线程。    

    3.自定义线程工厂

      每个静态的ExecutorService创建方法都被重载为接受一个ThreadFactory对象,该对象将被用来创建新的线程。例如:

    public class TaskDaemonFactory implements ThreadFactory{
        public Thread newThread(Runnable r){
            Thread t = new Thread(r);return t;
        }
    }

      想使用自己定义的线程工厂

      ExecutorService exec = Executors.newCachedThreadPool(new TaskDaemonFactory());

      这样可以通过具体的要求来改造线程。

    注:以上代码均来自《Thinking in java》,内容均来自个人理解与总结,如有理解错误,请大家批评指正

  • 相关阅读:
    进程和程序的关系
    进程和线程区别和联系
    什么是进程,进程的特征
    23.each和map函数
    22.仿淘宝五角星评论(链式编程、隐式迭代)
    19.阻止事件冒泡e.stopPropagation();
    18.阻止默认操作e.preventDefault();防止冒泡事件:e.stopPropagation()
    15.仿腾讯固定导航栏
    14.仿京东右侧边导航栏
    算法学习:树上差分
  • 原文地址:https://www.cnblogs.com/brolanda/p/4703948.html
Copyright © 2011-2022 走看看