状态依赖性的管理

可阻塞的状态依赖操作的形式如下:

  1. 构成前提条件的变量必须由对象的锁来保护, 从而使它们在测试前提条件的同时保持不变
  2. 如果前提条件未满足, 就必须释放锁, 以便其他线程可以修改锁的状态
  3. 在再次测试前提条件之前必须重新获取锁

image.png

有界缓存示例

有界缓存:

  • put操作的前提条件是不能从空缓存中获取元素
  • take操作的前提条件是不能往已满的缓存中放元素

image.png

将前提条件的失败传递给调用者

image.png
image.png

  • 前提条件失败后进入休眠, 避免消耗过多的CPU时间, 但是响应性低
  • 也可以重新调用take方法, 进入忙等待(也叫自旋等待), 但会消耗大量的CPU时间
  • 也可以调用Thread.yield, 提示调度器, 让出一定的时间让另一个线程运行以提高效率

通过轮询和休眠来实现简单的阻塞

如下图, 将前提条件的管理操作封装了起来, 从而使调用者无须在每次调用时都实现重试逻辑, 简化了缓存的使用
image.png

条件队列

条件队列的名字来源于: 它使得一组线程(等待线程集合)能够通过某种方式来等待特定的条件变成真. 传统队列的元素是一个个数据, 而与之不同的是, 条件队列中的元素是一个个正在等待相关条件的线程

  • Object.wait会自动释放锁, 并请求操作系统挂起当前线程, 从而使其他线程能够获得这个锁并修改对象的状态
  • 条件队列使得在表达和管理状态依赖性时更加高效

image.png

使用条件队列

  • 关键是找出对象在哪个条件谓词上等待, 条件谓词是使某个操作成为状态依赖操作的前提条件

image.png