5、Executor框架

Executor框架是并发集合java.util.concurrent中的一个成员。

Executor为灵活且强大的异步任务执行框架提供了基础,还提供了对生命周期的支持,以及统计信息、应用管理机制和性能监视等机制。
Executor 最早是为了解决生产者-消费者模式而引入的。提交任务相当是生产者,执行任务相当是消费者。

线程池:(翻译的文档):
线程池和工作者队列密切相关,工作者线程的任务:从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务。
Executors类里面提供了一些静态工厂,生成一些常用的线程池。
newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
newSingleThreadScheduledExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。

线程池Executor任务拒绝策略(翻译的文档):
java.util.concurrent.RejectedExecutionHandler描述的任务操作。
第一种方式直接丢弃(DiscardPolicy)
第二种丢弃最旧任务(DiscardOldestPolicy)
第三种直接抛出异常(AbortPolicy)
第四种任务将有调用者线程去执行(CallerRunsPolicy)

生命周期(翻译的文档):
java.util.concurrent.ExecutorService 接口对象来执行任务,该接口对象通过工具类java.util.concurrent.Executors的静态方法来创建。 Executors此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。
ExecutorService扩展了Executor并添加了一些生命周期管理的方法。一个Executor的生命周期有三种状态,运行 ,关闭 ,终止。
Executor创建时处于运行状态。当调用ExecutorService.shutdown()后,处于关闭状态,isShutdown()方法返回true。这时,
不应该再想Executor中添加任务,所有已添加的任务执行完毕后,Executor处于终止状态,isTerminated()返回true。
shutdown():执行平缓的关闭过程,不再接受新的任务,同时等待已经提交的任务执行完成。
shutdownNow();执行粗暴的关闭过程,尝试取消所有运行中的任务,并且不再启动队列中尚未开始启动的任务。
awaitTermination: 这个方法有两个参数,一个是timeout即超时时间,另一个是unit即时间单位。
这个方法会使线程等待timeout时长,当超过timeout时间后,会监测ExecutorService是否已经关闭,若关闭则返回true,否则返回false。一般情况下会和shutdown方法组合使用。
ExecutorService service = Executors. newFixedThreadPool(3);  
         for ( int i = 0; i < 10; i++) {  
             System. out.println( "创建线程" + i);  
             Runnable run = new Runnable() {  
                 @Override  
                 public void run() {  
                     System. out.println( "启动线程");  
                 }  
             };  
             // 在未来某个时间执行给定的命令  
             service.execute(run);  
         }  
         // 关闭启动线程  
         service.shutdown();  
         // 每隔1秒监测一次ExecutorService的关闭情况.  
         service.awaitTermination(1, TimeUnit. SECONDS);  
         System. out.println( "all thread complete");

System. out.println(service.isTerminated());

6、锁机制引入的死锁、活锁和饥饿
加锁机制的目的是保证线程安全,但如果过度使用锁,会导致死锁等。我们使用线程池和信号量来限制对资源的限制。但这些被限制的行为可能导致死锁。
死锁:进程之间互相争夺资源导致系统无法向前运行的一种僵死状态,如果没有外力作用下系统很难继续向前运行。请参考我的博客多线程。
饥饿:当线程无法访问到它所需要的资源而不能继续执行时,就会发生饥饿。引发饥饿的最常见资源就是CUP的时钟周期。
活锁:liveLock是进程的状态还在发生变化但是不再继续向前运行的状态。

7、线程的开销:
(1)、上下文切换。cpu在做线程切换的时候,需要保存当前线程执行的上下文,并且新调度进来的线程执行上下文设置为当前上下文。
发生越多的上下文切换,增加了调度开销,并因此降低吞吐量。
(2)、内存数据的同步。synchronized发生隐式锁竞争的地方带来的开销会影响其它线程的性能。
(3)、阻塞。当在锁上发生竞争时,竞争失败的线程会阻塞,即所谓的竞态条件。JVM通过循环不断的尝试获取锁,直到成功。或者通过操作系统挂起阻塞的线程。
如果时间短,采用等待方式,如果时间长才适合采用线程挂起的方式。串行操作降低可伸缩性,并行切换上下文也会降低性能。
在锁发生竞争时,会同时导致上面两种问题,因此,减少锁的竞争能够提高性能和收缩性。在并发程序中,
对可伸缩性最主要的威胁就是独占方式的资源锁。两个因素将影响锁上面发生竞争的可能性:锁的请求频率以及每次持有该锁的时间。
如果两者的乘积很小,那么大多数获取锁操作都不会发生竞争。

三种方式可以降低锁的竞争程度:
(1)、降低锁的请求频率。
降低线程请求锁的频率,可以通过锁分解和锁分段等技术来实现。即减小锁的粒度。如果一个锁同时需要保护好几个状态变量,那么可以把这个锁分解成多个锁,并且每个锁只保护一个状态变量,从而提高可伸缩性,并最终降低每个锁的请求频率。但是使用的锁越多,发生死锁的风险也会越高。

(2)、减少锁的持有时间。
减少被锁部分的加锁时间。缩小锁的范围(快进快出),可以将一些与锁无关的代码移出同步代码块,尤其是开销较大的操作,以及可能被阻塞的操作,比如I/O 操作。

(3)、减少使用独占锁,并发容器,读-写锁,不可变对象以及原子变量。

独占锁是一种悲观的技术。它假设最坏的情况发生(如果不加锁,其它线程会破坏对象状态),即使没有发生最坏的情况,仍然用锁保护对象状态

8、原子变量
原子性
采用锁技术会导致对锁的竞争导致系统性能降低。 当一个线程正在等待锁时,它不能做任何其他事情。如果一个线程在持有锁的情况下被延迟执行,那么所有需要这个锁的线程都无法执行下去。
原子性是指cpu在执行每一段代码时是不能被中断的。对除了long和double的基本类型的数据的简单操作都是原子的。例如a = 1; return a;
原子变量支持不用锁保护就能原子性更新操作,其底层用CAS实现。
一共有12个原子变量,可分为4组:标量类、更新器类、数组类以及复合变量类。

最常用的原子变量就是标量类:AtomicInteger、AtomicLong、AtomicBoolean以及AtomicReference。所有类型都支持CAS。

JVM对CAS的支持
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
CAS典型使用模式是:首先从V中读取A,并根据A计算新值B,然后再通过CAS以原子方式将V中的值由A变成B(只要在这期间没有任何线程将V的值修改为其他值)。
转载的博文:http://blog.csdn.net/csujiangyu/article/details/44002463
说明比较并交换的行为(而不是性能)的代码:
public class SimulatedCAS {
     private int value;

public synchronized int getValue() { return value; }

public synchronized int compareAndSwap(int expectedValue, int newValue) {
         int oldValue = value;
         if (value == expectedValue)
             value = newValue;
         return oldValue;
     }
}
使用比较并交换实现计数器:
public class CasCounter {
    private SimulatedCAS value;
    public int getValue() {
        return value.getValue();
    }
    public int increment() {
        int oldValue = value.getValue();
        while (value.compareAndSwap(oldValue, oldValue + 1) != oldValue)
            oldValue = value.getValue();
        return oldValue + 1;
    }
}

非阻塞同步机制

非阻塞算法的定义:一个线程的失败或者挂起,不会影响其它线程的失败或者挂起。
非阻塞算法提供比synchronized机制更高的性能和可收缩性。可以使多个线程在竞争相同的数据时候不会发生阻塞。
基于锁的算法中可能会出现各种活跃性的障碍,比如I/O 阻塞,导致其它线程都无法进行下去,导致性能下降。

java并发编程实战阅读总结(b)相关推荐

  1. java并发编程实战阅读总结(a)

    1.锁(lock)与volatile (1).隐式锁,java提供了强制原子性的内置锁机制:synchronized块或synchronized方法. 操作共享状态的复合操作必须是原子的,以避免竞态条 ...

  2. 第十一章 性能与可伸缩性 Java并发编程实战 阅读总结

    线程的最主要目的是提高程序的运行性能. 线程可以使程序更加充分地发挥系统的可用处理能力, 从而提高系统的资源利用率. 此外, 线程还可以使程序在运行现有任务的情况下立即开始处理新的任务, 从而提高系统 ...

  3. 前置条件,不变性条件,后置条件 --《java并发编程实战》

    阅读<java并发编程实战>4.1.1章 收集同步需求时, 反复出现了"不变性条件","不可变条件","后验条件",令我一头雾水 ...

  4. Java并发编程实战笔记2:对象的组合

    设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...

  5. aqs clh java_【Java并发编程实战】—– AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...

  6. java 多线程缓存_[Java教程]【JAVA并发编程实战】12、使用condition实现多线程下的有界缓存先进先出队列...

    [Java教程][JAVA并发编程实战]12.使用condition实现多线程下的有界缓存先进先出队列 0 2016-11-29 17:00:10 package cn.study.concurren ...

  7. Java并发编程实战————恢复中断

    中断是一种协作机制,一个线程不能强制其他线程停止正在执行的操作而去执行其他操作. 什么是中断状态? 线程类有一个描述自身是否被中断了的boolean类型的状态,可以通过调用 .isInterrupte ...

  8. Java并发编程实战————Executor框架与任务执行

    引言 本篇博客介绍通过"执行任务"的机制来设计应用程序时需要掌握的一些知识.所有的内容均提炼自<Java并发编程实战>中第六章的内容. 大多数并发应用程序都是围绕&qu ...

  9. Java并发编程实战————Semaphore信号量的使用浅析

    引言 本篇博客讲解<Java并发编程实战>中的同步工具类:信号量 的使用和理解. 从概念.含义入手,突出重点,配以代码实例及讲解,并以生活中的案例做类比加强记忆. 什么是信号量 Java中 ...

最新文章

  1. 如何搭建亿级社交信息分享社交平台架构
  2. 谷歌程序员少输一个“”,差点让全球Chrome笔记本变砖
  3. Android Studio获得sha1码
  4. net.sf.json在处理json对象转换为普通java实体对象时的问题和解决方案
  5. 国内开源软件镜像网站大全
  6. Android变形(Transform)之Camera使用介绍【转】
  7. hdu1521 指数型母函数
  8. TM4C123核心板焊接须知
  9. c语言八数码A星算法代码解析,八数码问题c语言a星算法详细实验报告含代码解析...
  10. xshell添加vbs脚本
  11. 【开源】MagicData-RAMC :180小时中文对话式语音数据集正式发布
  12. Mel中级教程精华篇预告
  13. ubuntu18.04(Jetson)以及火狐浏览器设置终端代理和清除代理命令
  14. python编程游戏-9个Python编程小游戏,有趣又好玩,简直太棒了
  15. Multisim学习(一)电路的绘制
  16. 保险业的5项CX预测
  17. 猿链猿哥:IKO,Initial Keepsake Offering,首次纪念品发行
  18. agv机器人无人仓系统-仓库控制模块设计
  19. DGA(域名生成算法)/DNS tunnel
  20. codeforces contest 1166 E. The LCMs Must be Large---思维

热门文章

  1. JavaScript 专题之函数柯里化
  2. CodePlex关闭,建议迁移至GitHub
  3. JavaScript强化教程 —— Cocos2d-JS极速调试技巧
  4. static方法不能直接访问类内的非static变量和不能调用this,super语句分析
  5. HTML5实现Word中文字全环绕图片效果
  6. C#基础:Lambda表达式
  7. Thread.yield()和Thread.sleep(0)
  8. linux无法访问443端口,linux – 为什么我无法在Ubuntu上ping端口443?
  9. tornado学习笔记day03-响应输出
  10. pytorch神经网络因素预测_实战:使用PyTorch构建神经网络进行房价预测