总结:Java锁机制

那年仲夏 提交于 2020-02-26 09:59:57

一、  synchronized

原生关键字

二、  Lock

lock()方法:获取锁,被占用则等待,直到等到为止,即阻塞式获取;

lock.lockInterruptibly()方法:类似lock(),唯一不同的是,这个获取(阻塞)过程可以代码去中断的,即假设B线程在等待A线程的锁,B线程可以通过调用interrupt()方法中断自己的等待。注意:只能中断阻塞线程,不会中断执行中的线程更确切 的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞, 那么,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。

tryLock():非阻塞式获取,即获取不到不会等待,立即返回失败

tryLock(long time, TimeUnit unit):非阻塞式获取,即获取不到,则会等待unit时间,如果还未获取到,则返回失败。

newCondition(): 返回一个绑定到lock对象上的condition对象,作用是处理一些条件下的问题,如边界问题(如数组满则不能put,数组空则不能take等) 

 

ReentrantLock,即 可重入锁。ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法。

参考:

Lock的lockInterruptibly()方法

Lock中为什么要使用多个Condition

三、  ReadWriteLock

自定义

四、  synchronized 与 Lock

Lock提供了比synchronized更多的功能。但是要注意以下几点:

    1)synchronized是Java语言的关键字,因此是内置特性,Lock不是Java语言内置的,Lock是一个接口,通过实现类可以实现同步访问。

    2)synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中

    3)在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态。

参考:

java 锁 Lock接口详解

Synchronized与ReentrantLock区别总结(简单粗暴,一目了然)

五、可重入锁与不可重入锁

可重入锁, 即一个线程可以进入任何一个 该线程 已经拥有的锁所同步着的代码块 。

参考: https://www.cnblogs.com/xdyixia/p/9383388.html

六、关于公平锁和非公平锁

公平锁:首先判断当前AQS的state是否等于0,锁是否被占用,如果没有被占用的话,继续判断队列中是否有排在前面的线程在等待锁,没有的话就修改statte状态
然后将当前线程记录为独占锁的线程,继续判断当前线程是否为独断锁的线程,ReentrantLock是可冲入的,线程可以不停地Lock来增加state的值,对应的需要unlock来解锁,减少state的值
如果上面的条件判断失败,即获取锁失败,则将线程加入到等待线程队列队尾,然后阻塞线程,等待被唤醒

 

非公平锁:非公平锁逻辑基本跟公平锁一致,最本质的区别是,当当前的锁状态没有被占用时,当前线程可以直接占用,而不需要判断当前队列中是否有等待线程。

参考:

关于公平锁和非公平锁

七、AQS

AQS即 AbstractQueuedSynchronizer类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch...。

它维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。这里volatile是核心关键词,具体volatile的语义,在此不述。state的访问方式有三种:

  • getState()
  • setState()
  • compareAndSetState()

AQS定义两种资源共享方式:Exclusive(独占,只有一个线程能执行,如ReentrantLock)和Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。

 

参考:Java并发之AQS详解

八、

 

九、AtomicInteger原理

利用的CAS原理: CAS的思想很简单,三个参数,一个当前内存值V、旧的预期值A、即将更新的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false。

AtomicInteger主要作用是解决i++不是原子操作的问题,i++在并发程序下,可能会导致i的数值不对,使用AtomicInteger则不会。

java的并发原子包里面提供了很多可以进行原子操作的类,比如:

  • AtomicInteger
  • AtomicBoolean
  • AtomicLong
  • AtomicReference

我们知道基本类型的赋值操作是原子操作,但是类似这种i++的操作并不是原子操作,通过反编译代码我们可以大致了解此操作分为三个阶段:

tp1 = i;  //1
tp2 = tp1 + 1;  //2
i = tp2;  //3

如果有两个线程m和n要执行i++操作,因为重排序的影响,代码执行顺序可能会发生改变。如果代码的执行顺序是m1 - m2 - m3 - n1 - n2 - n3,那么结果是没问题的,如果代码的执行顺序是m1 - n1 - m2 - n2 - m3 - n3那么很明显结果就会出错。

参考:

AtomicInteger原理

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!