《Java并发编程实战》第8章学习笔记

第六周学习心得

一、线程池的使用
  • 在线程池的使用过程中,任务与任务的执行策略中存在有隐性的耦合,不同类型的任务需要规定不同的执行策略。

    • 依赖性任务:提交给线程池的任务需要依赖其他的任务才能执行,需要对任务的执行策略(线程池的大小、配置参数)进行约束,否则将产生活跃性问题。
    • 使用线程封闭机制的任务:将对象资源封闭在单线程的任务线程中执行时,不需要保证对象资源是线程安全的,所以如果将Executor从单线程环境改为线程池环境将会失去线程安全性。
    • 对响应时间敏感的任务:对响应时间敏感的任务应当放入线程数量适宜的线程池中执行,如果将多个运行时间较长且对响应时间敏感的任务提交到只包含少量线程的线程池中执行,将会降低系统的响应性。
    • 使用ThreadLocal的任务:只有当线程本地存储值的生命周期受限于任务的生命周期时,在线程池中使用ThreadLocal才会有意义,而在线程池的线程中不应该使用ThreadLocal在任务之间传递值。
  • 执行依赖性任务或者当线程池的大小不够大时,将有可能导致线程饥饿死锁。

  • 对于运行时间较长的任务,建议使用限时版本的可阻塞方法进行等待(例如:Thread.join(long)、Blocking.put(long)、Object.wait(long)),如果等待超时,可以主动的将任务标记为失败,然后中止任务或者将任务放回执行队列再次执行。可以有效减少等待时间。

  • 线程池的大小设置为***可用CPU数量+1***时,通常能实现最优的利用率。

    // 可以通过Runtime来获得当前可用CPU数目
    int N_CPUS = Runtime.getRuntime().avaliableProcessors();
    
ThreadPoolExecutor

ThreadPoolExecutor是一个灵活的、稳定的线程池,可以根据具体的条件进行线程池的各种定制。

// ThreadPoolExecutor的构造方法 
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler);

构造方法参数说明:

  1. corePoolSize:线程池的基本大小,也就是线程池的目标大小。

  2. maximumPoolSize:线程池的最大线程数,表示可同时活动的线程数量的上限。

  3. keepAliveTime:保活时间,如果某个线程的空闲时间超过了存活时间,那么将被标记为可回收的,并且当线程池的当前大小超过基本大小时,该线程将被终结。

    在 java 6中,可以通过allowCoreThreadTimeOut使线程池中的所有线程超时,如果希望这个线程池在没有任务的情况下能销毁所有线程,可以启用这个特性并将基本大小设置为0。

  4. uint:超时时间单元。

  5. workQueue:阻塞队列,用于缓存等待执行的任务。基本的任务排队方法有3种:无界队列、有界队列和同步移交(Synchronous Handoff)。

    • newFixedThreadPool和newSinglezzzThreadExecutor默认使用的是无界的LinkedBlockingQueue,如果任务持续快速的到达,并且超过了线程池处理它们的速度,那么任务队列将无限制的增加(最大为Integer.MAX_VALUE)。

    • *有界的ArrayBlockingQueue、LinkedBlockingQueue和ProrityBlockingQueue有助于避免资源耗尽的情况发生,但是当队列填满后,会限制任务执行的吞吐量。

    • SynchronousQueue并不是一个真正的队列,而是一种在线程之间进行移交的机制,要将一个元素放入该队列中,必须有另一个线程正在等待接受这个元素。只有当线程池是无界的或者可以拒绝任务时该队列才有价值。newCachedThreadPool工厂方法就是用的SynchronousQueue。

  6. threadFactory:可定制化线程的线程工厂,用于创建新线程。

  7. handler:饱和策略(任务拒绝策略,拒绝异常处理器)。任务拒绝策略,当阻塞队列满了,且线程池中的线程数达到maximumPoolSize,如果继续提交任务,就会采取任务拒绝策略处理该任务。

    • AbortPolicy:丢弃任务并抛出RejectedExecutionException异常,默认策略;

    • CallerRunsPolicy:由调用execute方法的线程执行该任务;

    • DiscardPolicy:悄悄丢弃任务,但是不抛出异常;

    • DiscardOldestPolicy:抛弃最旧的任务,然后尝试重新提交新任务。

    // 设置拒绝处理器代码实例
    ThreadPoolExecutor exec = new ThreadPoolExecutor(.........);
    exec.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunnerPolicy());
    

    核心实现原理分析

    相关资料参考链接:深入分析线程池的实现原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值