书籍作者:方腾飞 魏鹏 程晓明

第一章 并发编程的挑战

1.1 上下文切换

  1. 时间片一般是几十毫秒。
1
疑问:时间片与CPU的哪个属性有关?
  1. 任务从保存到再加载的过程就是一次上下文切换。
1
疑问:多个线程不没有产生竞争、阻塞或等待,也会发生上下文切换吗?
  1. 使用Lmbench3可以测量上下文切换的时长。
  2. 使用vmstat可以测量上下文切换的次数。
  3. 减少上下文切换的方法:
    1. 无锁并发编程
    2. CAS算法
    3. 使用最少线程
    4. 协程

1.2 死锁

避免死锁的常见方法:

  1. 避免一个线程同时获取多个锁。
  2. 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。
  3. 尝试使用定时锁,使用lock.tryLock(timeout)来替代使用内部锁机制。
  4. 对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。

1.3 资源限制的挑战

  1. 资源限制是指在进行并发编程时,程序的执行速度受限于计算机硬件资源或者软件资源。
  2. 在并发编程中,将代码执行速度加快的原则是将代码中串行执行的部分变成并发执行,但是如果将某段串行的代码并发执行,因为受限于资源,仍然在串行执行,这时候程序不仅不会加快执行,反而会更慢,因为增加了上下文切换和资源调度的时间。
  3. 对于硬件资源限制,可以考虑使用集群并行执行程序。对于软件资源限制,可以考虑使用资源池将资源进行复用。

第二章 Java并发机制的底层实现原理

2.1 volatile的应用

  1. 用volatile修饰的共享变量进行写操作的时候,虚拟机会在其代码中插入Lock前缀指令,该指令在多核处理器下会引发两件事情:
    1. 将当前处理器缓存行的数据写回到系统内存。
    2. 这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效。
1
这部分内容在《Java多线程实战指南》里说的更加详细

2.2 synchronized的实现原理与应用

  1. JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。代码块同步是使用monitorentermonitorexit指令实现的,而方法同步是使用另外一种方式实现的,细节在JVM规范里并没有详细说明。
  2. synchronized用的锁是存在Java对象头里的。如果对象是数组类型,则虚拟机用3个字宽存储对象头,如果对象是非数组类型,则用2字宽存储对象头。在32位虚拟机中,1字宽等于4字节。
长度 内容 说明
32/64bit Mark Word 存储对象的hashCode或锁信息等
32/64bit Class Metadata Address 存储到对象类型数据的指针
32/64bit Array length 数组的长度(如果当前对象是数组)