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

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;
}
}

【Java并发入门】03 互斥锁(上):解决原子性问题的更多相关文章

  1. Java并发编程实战 03互斥锁 解决原子性问题

    文章系列 Java并发编程实战 01并发编程的Bug源头 Java并发编程实战 02Java如何解决可见性和有序性问题 摘要 在上一篇文章02Java如何解决可见性和有序性问题当中,我们解决了可见性和 ...

  2. java 并发多线程显式锁概念简介 什么是显式锁 多线程下篇(一)

    目前对于同步,仅仅介绍了一个关键字synchronized,可以用于保证线程同步的原子性.可见性.有序性 对于synchronized关键字,对于静态方法默认是以该类的class对象作为锁,对于实例方 ...

  3. java并发多线程显式锁Condition条件简介分析与监视器 多线程下篇(四)

    Lock接口提供了方法Condition newCondition();用于获取对应锁的条件,可以在这个条件对象上调用监视器方法 可以理解为,原本借助于synchronized关键字以及锁对象,配备了 ...

  4. Java并发入门之FutureTask

    Java并发入门之FutureTask 前言: 最近遇到一个项目需要上传图片到服务器,API要求是二进制流,那就跑慢点一点点上传. 于是对多线程从没有应用过的我,决定拿多线程直接应用于代码. 应用Ex ...

  5. Java并发编程:Concurrent锁机制解析

    Java并发编程:Concurrent锁机制解析 */--> code {color: #FF0000} pre.src {background-color: #002b36; color: # ...

  6. python 并发编程 多进程 互斥锁 目录

    python 并发编程 多进程 互斥锁 模拟抢票 互斥锁与join区别

  7. Java并发编程之验证volatile不能保证原子性

    Java并发编程之验证volatile不能保证原子性 通过系列文章的学习,凯哥已经介绍了volatile的三大特性.1:保证可见性 2:不保证原子性 3:保证顺序.那么怎么来验证可见性呢?本文凯哥(凯 ...

  8. Java并发基础03. 传统线程互斥技术—synchronized

    在多个线程同时操作相同资源的时候,就会遇到并发的问题,如银行转账啊.售票系统啊等.为了避免这些问题的出现,我们可以使用synchronized关键字来解决,下面针对synchronized常见的用法做 ...

  9. Java并发编程:同步锁、读写锁

    之前我们说过线程安全问题可以用锁机制来解决,即线程必要要先获得锁,之后才能进行其他操作.其实在 Java 的 API 中有这样一些锁类可以提供给我们使用,与其他对象作为锁相比,它们具有更强大的功能. ...

  10. 悲观的并发策略——Synchronized互斥锁

    volatile既然不足以保证数据同步,那么就必须要引入锁来确保.互斥锁是最常见的同步手段,在并发过程中,当多条线程对同一个共享数据竞争时,它保证共享数据同一时刻只能被一条线程使用,其他线程只有等到锁 ...

随机推荐

  1. MySQL数据库中配置文件 read_only 参数的有关说明

    1.对于MySQL单实例数据库和master库,如果需要设置为只读状态,需要进行如下操作和设置: 将MySQL设置为只读状态的命令(可以登录mysql执行下面命令, 或者在my.cnf配置文件中添加& ...

  2. 现有rabbitmq集群添加新节点,移除旧节点(可以作为rabbitmq集群迁移使用)

    原有集群安装步骤:https://www.cnblogs.com/sanduzxcvbnm/p/15797788.html 1.拉取镜像 集群中新节点需要执行 docker pull rabbitmq ...

  3. Fluentd部署:如何监控Fluentd

    监控的目的是确保日志采集能稳定高效运行. Fluentd内部运行指标 Fluentd内部保存着一些运行指标,这些指标可通过REST api直接获取,也支持通过第三方工具,如Prometheus,来访问 ...

  4. typescript中对象属性可选属性与只读属性与索引签名

    可选属性 type类型别名 type 会给一个类型起个新名字. type 有时和 interface 很像,但是可以作用于原始值(基本类型),联合类型,元组以及其它任何你需要手写的类型. interf ...

  5. 请推荐下比较适合中小企业的ERP系统,如odoo,除前期开发和不定期完善,有没有其他固定月费或年费?

    odoo的话你自己就可以下载开源的安装使用的啊,如果你要别人帮你开发和完善做技术服务的话一般都还是要年费的,主要是因为要帮你做维护或修bug什么的,自己能搞定的话自然不需要的哦.只是odoo使用的是p ...

  6. vue3中pinia的使用总结

    pinia的简介和优势: Pinia是Vue生态里Vuex的代替者,一个全新Vue的状态管理库.在Vue3成为正式版以后,尤雨溪强势推荐的项目就是Pinia.那先来看看Pinia比Vuex好的地方,也 ...

  7. [CG从零开始] 6. 加载一个柴犬模型学习UV贴图

    在第 5 篇文章中,我们成功加载了 fbx 模型,并且做了 MVP 变换,将立方体按照透视投影渲染了出来.但是当时只是随机给顶点颜色,并且默认 fbx 文件里只有一个 mesh,这次我们来加载一个柴犬 ...

  8. CodeCraft-21 and Codeforces Round #711 (Div. 2)

    就ac了俩 A题求gcd>1,WA了好多发....因为感觉没错,结果后面一看n的数据10^18,原来是没用long long. 经验:今后一定要看看数据范围. B题,一开始没看懂题意,不知道什么 ...

  9. P1099 [NOIP2007 提高组] 树网的核 (树的直径)

    题目的意思就是在直径上找一段距离不超过s的路径,使该路径的偏心距最小. 求出直径之后,显然我们可以用双指针扫描一段合法路径.设u1,u2...ut是直径上的点,d[ui]表示从ui出发能到达的最远距离 ...

  10. P1886 滑动窗口 /【模板】单调队列 方法记录

    原题链接 滑动窗口 /[模板]单调队列 题目描述 有一个长为 \(n\) 的序列 \(a\),以及一个大小为 \(k\) 的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最 ...