原子性问题的源头是线程切换

Q:如果禁用 CPU 线程切换是不是就解决这个问题了?

A:单核 CPU 可行,但到了多核 CPU 的时候,有可能是不同的核在处理同一个变量,即便不切换线程,也有问题。

所以,解决原子性的关键是「同一时刻只有一个线程处理该变量,也被称为互斥」。

如何做到呢?用「锁」。

一、锁模型

一)简易锁模型

一般看到的锁模型长下面这样。

但对于这个模型,会有几个疑问:

  • 锁的是什么?
  • 临界区的这一堆代码相关的都被锁了?
  • 保护的又是什么?

二)改进后的锁模型

用下面这个模型来解释就解答了上面几个问题:

  • 要保护的是临界区中的资源 R
  • 因此要为 R 创建一个对应的锁 LR
  • 需要处理资源 R 的时候先加锁,处理完之后解锁

要注意的是:

  • 一个资源必须和锁对应,不能用 A 锁去锁 B 资源

二、Java 提供的锁技术

Java 提供了多种技术,这里仅谈及 Synchronized

Synchronized 关键字

Java 语言提供的 synchronized 关键字,就是锁的一种实现。synchronized 关键字可以用来修饰方法,也可以用来修饰代码块。

class X {
// 修饰非静态方法
synchronized void foo() {
// 临界区
}
// 修饰静态方法
synchronized static void bar() {
// 临界区
}
// 修饰代码块
Object obj = new Object();
void baz() {
synchronized(obj) {
// 临界区
}
}
}

Q:synchronized 没看到 lock 和 unlock?

A:在编译的时候会做转换,synchronized起始的地方加锁,结束的地方解锁。

Q:那么 synchronized 锁的是什么呢?

A:当修饰静态方法时,锁定的是当前类的 Class 对象,在上面的例子中就是 Class X;

当修饰非静态方法时,锁定的是当前实例对象 this。

当修饰代码块时,括号中写的是啥就锁啥。

(可能不准确)

Class 对象是用来保存类信息的,可以理解为元数据?

实例对象则是每一个 new 出来的特殊的个体

Synchronized 实例

public class SynchronizedTT  {
private int value = 0; //public void printValue() {
public synchronized void printValue() {
System.out.println(this.value);
} public synchronized void addValue() throws InterruptedException {
Thread.sleep(1000);
this.value += 1;
}
} // 开两个线程,一个先调用 addValue(),另一个后调用 printValue()

思考:如果 printValue() 不添加 synchronized 关键字,会造成什么样的结果?

A:有可能会先执行了 addValue 在执行 print 但得到的却是增加之前的数值。

三、锁和受保护资源的关系

要点:

  • 一把锁可以保护多个资源
  • 但是一个资源只能用一把锁保护
  • 受保护资源和锁之间的关联关系是 N:1 的关系

思考:如果用多把锁锁同一个资源会出现什么情况?

下面例子:

synchronized 是不同的锁,就和没锁一样。

public class SynchronizedTT  {
private static int value = 0; public synchronized void printValue() {
System.out.println(value);
} public synchronized static void addValue() throws InterruptedException {
Thread.sleep(1000);
value += 1;
}
}

最新文章

  1. webpack进阶构建项目(一)
  2. 【笔记5】用pandas实现矩阵数据格式的推荐算法 (基于物品的协同)
  3. weex 小结 -- <list>
  4. 关于 Block的使用
  5. python3 split( ) not enough values to unpack(expceted 2, got 1)
  6. Windows Services windows域账户管理
  7. 使用git建立本地仓储管理代码【转】
  8. oracle删除字段时候判断字段是否存在
  9. IE=edge,chrome=1的META信息详解
  10. Web 高性能开发汇总
  11. DZ 3.2 URL 伪静态配置 教程
  12. CH Round #55 - Streaming #6 (NOIP模拟赛day2)
  13. SPOJ GSS1 && GSS3 (无更新/更新单点,并询问区间最大连续和)
  14. Oracle树形结构查询之prior的理解
  15. Objective-C 使用核心动画CAAnimation实现动画
  16. perl学习笔记--搭建开发环境
  17. 32 ArcToolBox学习系列之数据管理工具箱——属性域(Domains)的两种创建及使用方式
  18. nginx php-fpm开启session
  19. idea 自动根据屏幕代码换行
  20. A2W,W2A等的使用

热门文章

  1. 【ceph】理解Ceph的三种存储接口:块设备、文件系统、对象存储
  2. ELK 性能优化实践 ---总结篇
  3. 使用cnpm创建vue项目(含离线安装)
  4. 【可视化大屏教程】用Python开发智慧城市数据分析大屏!
  5. PAT (Basic Level) Practice 1031 查验身份证 分数 15
  6. PAT (Basic Level) Practice 1008 数组元素循环右移问题 分数 20
  7. aardio + PowerShell 可视化快速开发独立 EXE 桌面程序
  8. 利用POI遍历出层级结构的excel表格
  9. day48-JDBC和连接池04
  10. 17.MongoDB系列之了解应用程序动态