分享好友 编程语言首页 频道列表

【Java并发入门】03 互斥锁(上):解决原子性问题

Java教程  2023-02-09 10:070

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

Q:如果禁用 CPU 线程切换是不是就解决这个问题了?
A:单核 CPU 可行,但到了多核 CPU 的时候,有可能是不同的核在处理同一个变量,即便不切换线程,也有问题。

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

如何做到呢?用「锁」。

一、锁模型

一)简易锁模型

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

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

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

image.png

二)改进后的锁模型

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

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

image.png

要注意的是:

  • 一个资源必须和锁对应,不能用 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()

查看更多关于【Java教程】的文章

展开全文
相关推荐
反对 0
举报 0
评论 0
图文资讯
热门推荐
优选好物
更多热点专题
更多推荐文章
java怎么自定义jstl标签库 jstl标签库有哪些标签
这篇“java怎么自定义jstl标签库”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“java怎么自定义jstl标签库”文章吧。开发环境:Spri

0评论2023-02-09825

Java分析Lambda表达式Stream流合并分组内对象数据合并
目录前言需求代码实现依赖引入设计实体类测试代码前言之前写过《Lambda使用——JDK8新特性》,现在有一个分组合并的需求正好拿来小试牛刀。需求数据出自许多接口数据,需要将几个接口数据根据省份id进行分组合并。举例说明:A接口返回List里面有值的的字段为

0评论2023-02-09990