并发编程(三)互斥锁:解决原子性问题

1.原子性问题如何解决

原子性的源头是线程切换。而前程切换是基于CPU中断实现的,那是不是让CPU无法中断,就能避免线程切换并保证原子性呢?

答案是不一定,在单CPU场景下或许可以这样,但是在多CPU场景下就行不通了,因为可能一个代码操作会多个线程在多个CPU同时执行,此时就无法保证CPU的原子性,此时多个线程同时执行,还是可能会产生竞态条件

那么该如何保证原子性呢?

这时候可以采取互斥机制:保证同一时刻,只有一个线程执行这一条件。也就是说保证对共享变量的修改时互斥的

2.互斥

2.1.简易锁模型

image-20210727195054838

临界区:一段需要互斥的代码

简易锁模型:线程进入临界区之前首先请求锁(尝试加锁)lock(),成功则进入临界区,失败则等待或返回(阻塞or非阻塞),持有锁的线上执行完临界区的代码后,执行解锁unlock()

2.2.改进后的锁模型

image-20210727195601805

这里我们将临界区的受保护的资源标注了出来,其次我们还将受保护的资源R与保护资源的锁LR相关联,这样就能有效避免锁别的临界区资源的情况

2.3.Java提供的锁机制:Synchronized

锁是一种通用解决方案,Java语言提供的Synchronized就是锁的一种实现。

其可以用来:

  1. 修饰非静态方法:

    锁定的是当前实例对象this

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

    锁定的是当前类的Class对象

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

    锁定的是指定的类对象实例

    // 修饰代码块
      Object obj = new Object();
      void baz() {
        synchronized(obj) {
          // 临界区
        }
      }
    

    Java 编译器会在 synchronized 修饰的方法或代码块前后自动加上加锁 lock() 和解锁 unlock(),这样做的好处就是加锁 lock() 和解锁 unlock() 一定是成对出现的,毕竟忘记解锁 unlock() 可是个致命的 Bug(意味着其他线程只能死等下去了)

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

受保护资源和锁的关系应该是N:1,也就是一把锁可以保护多个资源,也就是说对共享资源的读写应该是由一把锁来保护的,如果多把锁同时保护一个资源,会有什么问题呢?

例如如下:

在并发调用addOne()的时候,调用get()方法时就会导致value的可见性问题,因为此时value是被SafeCalc.class和this一起保护

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

synchronized是Java在语言层面的提供的互斥原语,其实Java还有很多其他类型的锁,但是作为互斥锁,原理都是相通的:锁,一定要有一个锁定的对象

3.如何用一个锁保护多个资源

3.1.保护没有关联的多个资源

前面也提到了,多个资源共用一把锁,当然是可以的,但是此时会导致针对没有关联的共享资源的访问都变为单线程,性能太差。

此时用不同的锁对受保护资源进行精细化管理,能够提升性能。这种锁还有个名字,细粒度锁

3.2.保护有关联关系的多个资源

如何定义资源存在关联关系:

简单来说,关联关系就是一种原子性特征:外在表现是不可分割,本质操作的中间状态对外不可见,面向CPU就是多核CPU执行互斥也不中断

image-20210727221241572

如果这个时候仍然使用一把锁进行保护,则可能出现锁无法覆盖所有的受保护资源(具体也需要看场景),而正确的做法是选择一个粒度更大的锁,这个锁应该能够覆盖所有相关的资源,总结如下:

加锁的原则:

不存在关联关系的资源,尽量用细粒度锁

存在关联关系的资源,需要使用能够覆盖所有受保护资源的锁,并且需要梳理出访问路径,所有访问路径都设置合适的锁。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×