zoukankan      html  css  js  c++  java
  • 第六章 任务执行

    • 1.创建线程的方式

      1.继承Thread类创建线程

      2.实现Runnable接口创建线程

      3.使用Callable和Future创建线程

      (参考:https://www.cnblogs.com/3s540/p/7172146.html)

    2.Executor框架——将任务的提交过程和执行过程解耦

    //通过execute()方法将任务提交到工作队列,工作线程反复从工作队列中取出任务并执行
    public
    interface Executor{ void execute(Runnable command); }

    3.线程池

      通过调用Executors中的静态工厂方法之一创建一个线程池:

      newFixedThreadPool:创建一个固定长度的线程池。

      newCachedThreadPool:创建一个可缓存的线程池,如果线程池的当前规模超过了处理需求,将回收空闲的线程;当需求增加时,将创建新的线程,线程池的规模不存在限制。

      newSingleThreadExecutor:创建一个单线程的Executor,它创建一个单工作者线程,当该线程异常结束时,会创建另一个线程替代它。确保任务按照在队列中的顺序串行执行。

      newScheduledThreadPool:创建一个固定长度的线程池,而且以延迟或定时的方式来执行任务。

    4.Executor的生命周期

      为了解决执行服务的生命周期问题,ExecutorService继承了Executor接口,添加了生命周期的管理方法

      

    public interface ExecutorService extends Executor{
        void shutdown();
        List<Runnable> shutdownNow();
        boolean isShutdown();
        boolean isTerminated();
        boolean awaitTermination(long timeout, TimeUnit unit)
        ...
    }

    ExecutorService的生命周期有3中状态:运行,关闭和已终止

    ExecutorService在初始创建时处于运行状态。

    shutdown方法将执行平缓的关闭过程:不再接受新的任务,同时等待已经提交的任务执行完成——包括那些还未开始的任务。shutdownNow方法将执行粗暴的关闭过程:将尝试取消所有运行中的任务,并且不再启动队列中尚未开始执行的任务。

    等所有任务完成以后,ExecutorService进入终止状态。

    继续细分:

      1.RUNNING:线程池创建完毕后

      2.SHUTDOWN:RUNNING的下个状态之一,不接受新任务,但是会处理现有的任务,包括任务队列中的任务

      3.STOP:RUNNING的下个状态之一,不接受新任务并且尝试取消正在进行的任务,也不会继续处理任务队列中的任务

      4.TIDYING:2、3的下一个状态,这个时候所有任务均已终止,执行钩子函数

      5.TERMINATED:4的下一个状态,已终止

    有关线程池的更多内容请见:https://www.cnblogs.com/walker993/p/14615252.html

    5.携带结果的任务Callable与Future

      Runnable:不能返回一个值或抛出一个受检查的异常。

      Callable:call()方法将返回一个值或抛出一个异常。

      Future:表示一个任务的生命周期,并提供了相应的方法来判断是否已经完成或取消,以及获取任务的结果和取消任务等。get()方法取决于任务的状态(尚未开始,正在执行,已经完成)。当任务已经完成时,get将返回结果或抛出异常;如果任务没有完成,get将阻塞;如果任务抛出了异常,那get将该异常封装为ExecutionException并重新抛出。

    6. 线程间的通信方式

    1. 等待/唤醒机制
    2. 栅栏
    3. 闭锁
    4. 信号量

      http://www.cnblogs.com/PerkinsZhu/p/7439330.html

    7. 线程的调度

      调度方式:

    • 抢占式调度:每个线程由系统分配执行时间,线程的切换不由线程本身决定
    • 协同式调度:线程的执行时间由线程本身控制,线程把自己的工作执行完之后,主动通知系统切换到另外一个线程上。

      线程的调度算法:

    • 先来先服务:按照作业进入队列的时间顺序分配资源、创建线程
    • 短作业优先:从后备队列选取若干执行时间最短的作业,调入内存运行
    • 优先权调度:按优先级顺序分配
    • 时间片轮转:将任务按先来先服务原则拍成一个队列,每次调度时,把CPU分配给队首进程,令其执行一个时间片,时间片用完后,计时器时钟发出中断请求,调度程序停止该进程的执行,把它送到队列末尾,让队首的进程获取新的时间片 

    8. ThreadLocal

      每个线程内部都有一个ThreadLocals变量,实则为一个map类型的ThreadLocal.ThreadLocalMap的成员变量,map的key为当前的ThreadLocal,value为保存的变量的副本。

      https://www.cnblogs.com/dolphin0520/p/3920407.html

      这里讨论下ThreadLocal的内存泄漏问题,map的key是一个弱引用,当对应的ThreadLocal置为空时,ThreadLocalMap释放对ThreadLocal的引用,让GC回收ThreadLocal实例。但是,value并没有被回收,存在一条从currentThread连接过来的强引用,只有在当前线程结束之后才会被回收。所以,在线程池的环境中,因为线程的复用,会导致内存泄漏。解决方法是调用ThreadLocal的remove方法。

      https://www.cnblogs.com/jcli/p/talk_about_threadlocal.html,https://www.cnblogs.com/onlywujun/p/3524675.html

    9. 线程状态

      补一下线程状态的解析,引用一个很好的博文:https://www.cnblogs.com/waterystone/p/4920007.html

    人生就像蒲公英,看似自由,其实身不由己。
  • 相关阅读:
    Jenkins + GitLab 通过 Webhook 自动触发构建爬坑记录
    Spring Cloud Eureka 学习记录
    [源码分析]ArrayList
    一个简单的统计问题(解决方案:Trie树)
    Redis基本数据类型命令汇总
    Redis的Pub/Sub客户端实现
    从ByteBuffer中解析整数
    学习T-io框架,从写一个Redis客户端开始
    折腾一下WebSocket的ArrayBuffer传输方式
    Ubuntu安装docker笔记
  • 原文地址:https://www.cnblogs.com/walker993/p/9291076.html
Copyright © 2011-2022 走看看