zoukankan      html  css  js  c++  java
  • 第一部分:并发理论基础03->互斥锁(上),解决原子性问题

    1.原子性

    一个或多个操作在cpu执行的过程中不被中断的特性,称为原子性

    2.如何解决原子性问题

    源头是执行一半线程切换,禁止线程切换是不是就可以了?
    操作系统的线程切换,是操作系统自己控制cpu进行的,所以禁止操作系统的cpu发生中断就可以禁止线程切换

    单核cpu场景,同一时刻只有一个线程执行,禁止cpu中断,操作系统就不会重新调度线程,禁止了线程切换,获取cpu使用权的线程就可以不间断执行。两次写操作,要么都被执行,要么都没有被执行,具有原子性

    多核cpu场景,同一时刻,可能2个线程同时运行,一个线程在cpu1核上,一个线程在cpu2核上,禁止cpu中断,只能保证cpu上的线程连续执行不被线程切换走,不能保证同一时刻只有一个线程执行。

    同一时刻,只有一个线程执行,这个条件非常重要,我们成为互斥。我们对共享变量的修改,是互斥的,无论是单核还是多核cpu,都能保证原子性

    3.简易锁模型

    互斥,锁。
    image
    需要互斥执行的代码成为临界区。线程进入临界区之前,尝试加锁,如果成功,进入临界区。线程持有锁,否则就等待,直到持有锁的线程解锁。持有锁的线程执行完临界区代码后,解锁unlock

    类比进坑锁门,出坑开门,如厕就是临界区。

    4.改建的锁模型

    锁和资源的关系
    image

    创建和资源关联的锁

    5.java语言提供的同步锁synchronized

    synchronized就是锁的一种实现,synchronized关键字可以修饰方法,修饰代码库,

    代码范例

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

    synchronized 默认加上了加锁,解锁操作。
    synchronized修饰代码库的时候,锁定了obj对象
    synchronized修饰方法时候,锁定的是当前实例对象this
    synchronized修饰静态方法时候,锁定的是当前类的class对象
    修饰静态方法的具体含义

    
    class X {
      // 修饰静态方法
      synchronized(X.class) static void bar() {
        // 临界区
      }
    }
    

    修饰非静态方法的具体含义

    
    class X {
      // 修饰非静态方法
      synchronized(this) void foo() {
        // 临界区
      }
    }
    

    6.多线程共享数据修改问题

    synchronized

    
    class SafeCalc {
      long value = 0L;
      long get() {
        return value;
      }
      synchronized void addOne() {
        value += 1;
      }
      long get() { return value; }
    }
    

    synchronized修饰addOne方法后,一定能保证原子操作,
    可见性呢?
    6个happens-before中的管程中锁规则说明了,对锁的解锁happens-before与后续对这个锁的加锁操作

    管程就是synchronized,synchronized修饰的临界区是互斥的,同一时刻只有一个线程执行临界区的代码

    而解锁操作happens-before后续对这个锁的加锁操作。
    多线程同时之同时addOne方法,可见性是保证的,A线程修改完后,解锁happens-before与B线程的加锁,数据的可见性有保证

    get方法可见不?
    答案是不可见,管程中只保证后续对这个锁的加锁的可见性,get方法没有加锁,所以没法保证可见性,优化成synchronized修饰就可以解决这个问题了
    get和addOne用的是一把锁this
    image

    7.锁和受保护资源的关系

    受保护资源和缩之间的关系是N:1,一把锁保护多个资源可以,多把锁保护一个资源不可行

    
    class SafeCalc {
      static long value = 0L;
      synchronized long get() {
        return value;
      }
      synchronized static void addOne() {
        value += 1;
      }
    }
    

    修改数据用的是SafeCalc.class锁,而get()用的是this锁,
    修改数据的synchronized可见性只保证向同锁的可见性
    这两个临界区没有互斥关系,所以有并发问题了

    8.总结

    互斥锁,需要深知锁的对象和缩之间的关系,才能用好互斥锁。

    原创:做时间的朋友
  • 相关阅读:
    C#的System.Diagnostics.Trace.WriteLine 写入到文件中案例
    ubuntu开放指定端口
    mysql 启报错报 The server quit without updating PID file
    【WebMisCentral WMC】基于Extjs 4.2x的企业级用户授权认证中心系统(SSO+AM+SM),多租户SAAS应用
    Ajaxupload.js在最新版chrome 83版浏览器oncomplete失效问题解决方法
    SQLServer 父子结构group汇总显示
    jqweui 关于$(document.body).infinite的bug
    EntityFramework 动态构造排序 Func<IQueryable<T>, IOrderedQueryable<T>> Dynamic
    Safari 3D transform变换z-index层级渲染异常的研究
    Asp.net Core中使用NLog,并封装成公共的日志方法
  • 原文地址:https://www.cnblogs.com/PythonOrg/p/14931096.html
Copyright © 2011-2022 走看看