码迷,mamicode.com
首页 > 编程语言 > 详细

Java中一些锁的概念理解

时间:2021-06-02 12:08:39      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:util   恢复   无锁编程   进入   次数   idt   mamicode   虚拟机   乐观锁和悲观锁   

技术图片

 

 

 

1.乐观锁和悲观锁

对于同一个共享资源,悲观锁认为,在自己使用数据的时间内,一定会有其它的线程来使用该数据,所以必须要对这个共享资源进行上锁,如果不上锁,在这期间数据可能会被其它的线程锁修改。java中的synchronizedLock的实现类都是悲观锁。

 

而对于乐观锁而言,认为自己在使用共享资源期间,其它的线程不会修改共享资源,所以不会上锁,只是在更新这个共享资源的时候,去判断有没有其它的线程更新了这个数据,如果没有更新,则直接更新,如果更新了,则采取相应的处理方法。乐观锁在java中是通过使用无锁编程来实现的,最常用的是CAS算法。java中的原子类就是通过CAS自旋来实现的。

 

由以上可知悲观锁适合写多的操作,因为这样可以保证共享资源的准确性。乐观锁适合多读的操作,这样多个线程对数据的读操作,就不用等待获取锁。

 

乐观锁和悲观锁在使用方式也有差别,悲观锁往往需要在获取锁和释放锁之间进行同步操作,而乐观锁直接进行操作就好了。

 

 

乐观锁是如何实现不锁住对象,也能保证线程的同步呢。

 

CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。

 

 

最常见的就是Java.util.current类中的原子类,通过自旋的方式来实现变量同步。

 

 

 

2。自旋锁和适应性自旋锁

 技术图片

 

在唤醒线程或阻塞线程需要CPU切换状态,如果cpu切换状态的时间比代码执行的时间还长,那明显是不合适的。

 

在许多场景中,同步资源的锁定时间很短,为了这一小段时间去切换线程,线程挂起和恢复现场的花费可能会让系统得不偿失。如果物理机器有多个处理器,能够让两个或以上的线程同时并行执行,我们就可以让后面那个请求锁的线程不放弃CPU的执行时间,看看持有锁的线程是否很快就会释放锁。而为了让线程等待一下,我们就需要让当前的线程进行自旋,如果在自旋完成后前面锁定同步资源的线程已经释放了锁,那么当前线程就可以不必阻塞而是直接获取同步资源,从而避免切换线程的开销。这就是自旋锁。

 

 

自旋锁缺点就是不能代替堵塞,虽然自旋锁节省了cpu切换线程的开销,但是占用了cpu的时间,如果锁被占用的时间很短,那么自旋的效果就会很好,但是如果锁被占用的时间很长,那么只会白白的浪费处理器的时间,

 

 

 

 

 

 

 

 

 

 

 

自适应意味着自旋的时间(次数)不再固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也是很有可能再次成功,进而它将允许自旋等待持续相对更长的时间。如果对于某个锁,自旋很少成功获得过,那在以后尝试获取这个锁时将可能省略掉自旋过程,直接阻塞线程,避免浪费处理器资源。

 

 

 

 

 

 

 

4.公平锁和非公平锁

 

公平锁是指,在多个线程安装申请获得锁的顺序来获取锁,只有最先申请锁的线程才能获取锁,其它申请同一个锁的线程全部进入阻塞状态,并按照申请锁的顺序进行排队获取锁。

非公平锁则不存在排队的问题,多个线程获取同一个锁,只要获取了锁,该线程就能运行,不管这个线程是否是第一个申请锁的线程,其它的线程全部进入阻塞状态。

 

公平锁与非公平锁内部的实现机制就是差一个同步队列,公平锁在每次获取锁的时候,都会判断当前线程是否是同步队列的第一个线程。

 

 

 

 

重入锁和非重入锁

 

重入锁表示的是如果一个线程获取了某个对象或者class的锁,那么该对象的多个同步方法都是可以进行调用的,如果是非重入锁,那么在线程获取锁后只能调用对象或class的一个同步方法或代码块,因为在调用对象的第2个同步区域时,上一个同步区域为执行完毕锁还未释放。

 

ReentrantLocksynchronized都是重入锁,重入锁和非重入锁最常见的类就是ReentrantLockNonReentrantLock,在类的内部其实维持了一个status变量,默认为0,如果有被获取锁一次就+1,释放就减1,对于重入锁,如果status的值为0,则直接获取锁,如果不是0,则判断当前申请锁的线程是否是之前获取锁的线程,在释放锁的时候通过依次-1来将status0,而对于非重入锁,如果status不等于0则直接进入阻塞状态,释放锁的时候之间将status归为0.

 

 

 

 

独享锁和共享锁

 

独享锁(排他锁)是指这个锁一次只能被一个线程所持有,如果线程A对数据加上了独享锁后,其它的线程不能在数据上再加锁了,获取排他锁后即能读又能写数据。synchronizedjuc中的Lock实现类就是独享锁。

 

共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁。获得共享锁的线程只能读数据,不能修改数据。

 

 

reentrantreadwritelock包括了独享锁和共享锁,内部包括readlock (共享锁),writelock(独享锁)。 

Java中一些锁的概念理解

标签:util   恢复   无锁编程   进入   次数   idt   mamicode   虚拟机   乐观锁和悲观锁   

原文地址:https://www.cnblogs.com/laoyu-love-life/p/14814962.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!