Java 中线程同步锁和互斥锁

一 概述

1.1 互斥

所谓互斥,就是不同线程,通过竞争进入临界区(共享的数据和硬件资源),为了防止访问冲突,在有限的时间内只允许其中之一独占性的使用共享资源。如不允许同时写。

1.2 同步

同步关系则是多个线程彼此合作,通过一定的逻辑关系来共同完成一个任务。一般来说,同步关系中往往包含互斥,同时,对临界区的资源会按照某种逻辑顺序进行访问。如先生产后使用。

1.3 两者区别

总的来说,两者的区别就是:互斥是通过竞争对资源的独占使用,彼此之间不需要知道对方的存在,执行顺序是一个乱序。同步是协调多个相互关联线程合作完成任务,彼此之间知道对方存在,执行顺序往往是有序的。

二 总结

纠结到底是同步锁还是互斥锁其实是没有什么意义的,你可以认为它们就属于一个东西,如果你只是抠这些概念的话,很容易陷入在一个"活锁"中,出也出不来。

在 Java 中,互斥锁就是两种,synchronized 和 Lock 接口的 xxxLock 实现类。但是道理都是一样的。无非就是哪种写起来更方便。

锁的目的就是避免多个线程对同一个共享的数据并发修改带来的数据混乱。如果存在线程安全性问题,一个非常有效的方式就是加锁,这里的同步锁和互斥锁其实就是一个意思。

锁在操作系统层面的意思就是 Mutex,互斥,意思就是说我(某个线程)获取锁(进入临界区)之后,其他线程不能再进入临界区,这样就达到了互斥的目的,如下图所示。
Java 中线程同步锁和互斥锁_第1张图片
锁的实现要处理的大概就只有以下4类问题:

  • “谁拿到了锁“,这个信息存哪里(可以是当前 class,当前 instance 的 markword,也可以是某个具体的 Lock 的实例)
  • 谁能抢到锁的规则(只能一个人抢到 - Mutex;能抢有限多个数量 - Semaphore;自己可以反复抢 - 重入锁;读可以反复抢到但是写独占 - 读写锁……)
  • 抢不到时怎么办(抢不到玩命抢;抢不到暂时睡着,等一段时间再试/等通知再试;或者二者的结合,先玩命抢几次,还没抢到就睡着)
  • 如果锁被释放了还有其他等待锁的怎么办(不管,让等的线程通过超时机制自己抢;按照一定规则通知某一个等待的线程;通知所有线程唤醒他们,让他们一起抢……)

有了这些选择,你就可以按照业务需求组装出你需要锁。

  • 互斥就是线程 A 访问了一组数据,线程 BCD 就不能同时访问这些数据,直到 A 停止访问了
  • 同步就是 ABCD 这些线程要约定一个执行的协调顺序。比如 D 要执行,B 和 C 必须都得做完,而 B 和 C 要开始,A 必须先得做完

这是两种典型的并发问题。恰当的使用锁,可以解决同步或者互斥的问题。

你可以说 Mutex 是专门被设计来解决互斥的;Barrier,Semaphore 是专门来解决同步的。但是这些都离不开上述对上述4个问题的处理。同时,如果遇到了其他的具体的并发问题,你也可以定制一个锁来满足需要。

你可能感兴趣的:(JAVA基础,java)