码农翻身之我是一个线程 --- 读书笔记
码农翻身之我是一个线程
文章目录
- 码农翻身之我是一个线程
- “我”的宿命 ——> 处理包裹
- 1.1 计算机世界规则
- 1.2 “我”的处理流程图
- “我”的小伙伴们
- “锁”出的问题
- 3.1 存取款操作需加锁后执行,例如:
- 3.2 死锁的发生
- 3.3 死锁的解决:新规则
1. “我”的宿命 ——> 处理包裹
1.1 计算机世界规则
- 不知何时被选中执行任务
- 执行过程中随时可能被打断
- 有硬盘、数据库等耗时操作需要让出CPU等待
- 数据来了也得等CPU挑选
1.2 “我”的处理流程图
2. “我”的小伙伴们
- Memcached 线程: 分布式缓存用户数据
- 数据库连接线程: 他们也有一个线程池
3. “锁”出的问题
3.1 存取款操作需加锁后执行,例如:
1 没加锁时操作情况
线程1:存入300元 | 线程2:取出200元 |
---|---|
获取当前余额:1000 | —— |
计算最新余额:1000 + 300 = 1300 | —— |
线程中断,等待下次系统挑中执行 | —— |
—— | 获取当前余额:1000 |
—— | 计算最新余额:1000 - 200 = 800 |
—— | 线程中断,等待下次被系统挑中执行 |
再次执行,更新余额:1300 | —— |
—— | 再次执行,更新余额:800 (存的钱丢了) |
2 加锁时操作情况
线程1:存入300元 | 线程2:取出200元 |
---|---|
获取账户A的锁:成功 | —— |
获取当前余额:1000 | —— |
计算最新余额:1000 + 300 = 1300 | —— |
线程中断,等待下次系统挑中执行 | —— |
—— | 获取账户A的锁:失败,进入阻塞状态 |
被系统选中,更新余额:1300 | —— |
释放账户A的锁 | —— |
—— | 获取账户A的锁:成功 |
—— | 获取当前余额:1300 |
—— | 计算最新余额:1300 - 200 = 1100 |
—— | 更新余额:1100 |
—— | 释放账户A的锁 |
3.2 死锁的发生
见下图:
线程1:演员 -> 导演 | 线程2:导演 -> 演员 |
---|---|
获取演员的锁:成功 | —— |
线程中断,等待下次系统挑中执行 | —— |
—— | 获取导演的锁:成功 |
—— | 线程中断,等待下次系统挑中执行 |
获取导演的锁:失败,继续等待 | —— |
—— | 获取演员的锁:失败,继续等待 |
最终只好干掉一个线程,来保证正常执行
3.3 死锁的解决:新规则
至此,新建立一个规则:获取资源的锁之前,必须先让所有资源统一进入一个算法,计算资源的优先级;并且永远按照从大到小的方式获取锁。如下表所示:
PS: 这里假设导演的优先级大于演员的优先级
线程1:演员 -> 导演 | 线程2:导演 -> 演员 |
---|---|
获取导演的锁:成功 | —— |
线程中断,等待下次系统挑中执行 | —— |
—— | 获取导演的锁:失败,继续等待 |
获取演员的锁:成功 | —— |
执行转账 | —— |
释放演员的锁 | —— |
释放导演的锁 | —— |
—— | 获取导演的锁:成功 |
—— | 获取演员的锁:成功 |
—— | 执行转账 |
—— | 释放演员的锁 |
—— | 释放导演的锁 |
注意:1. 释放锁的时候最好是从优先级小的资源开始释放
2. 所谓优先级的大小,实际就是将该资源变成一个数来比较,例如,用字符串的hashcode来比较。
后续内容更加精彩,江湖再见~
还没有评论,来说两句吧...