天天看点

几种常见锁的理解

对几种常见锁的理解:

悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行锁等),当其他线程想要访问数据时,被阻塞挂起。可以依靠数据库实现,如行锁,读锁,写锁等。Java中synchronized也是悲观锁思想。

乐观锁:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前,会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作。

Version机制:在数据库表中加一个数据version字段,表示数据被修改的次数。当数据被修改时version加一。读取数据同时也会读取到version值,当提交更新时,如果刚才读取的version值和当前数据库的version值相等才更新。否则重试更新操作,直到更新成功。

CAS操作:当需要更新数据时,判断当前内存值和之前取得的值是否相等。如果相等则用新值更新。若不等则失败,失败则重试,一般是一个自旋的过程,即不断重试。

自旋锁:线程的挂起和恢复操作都会转入内核态完成,这些操作给系统的并发性能带来很大压力。很多时候,共享数据的锁定状态只会持续很短一段时间。为了这么短的时间挂起和恢复线程不值得。如果计算机有一个以上的处理器,可以让两个线程同时并行执行,我们就会让后面那个线程稍等一下,但是不放弃处理器执行时间,看看持有锁的线程是否很快释放锁。为了让线程稍等一下,我们需要让线程执行一个忙循环(自旋),这项技术就是自旋锁。

自适应自旋锁:自适应表示自旋锁的自旋时间不再固定,根据前一次在这个锁上的自旋时间以及锁的拥有者的状态自动调整。例如:如果同一个锁对象,自旋等地刚刚获得多锁,那么这次再次获得这个锁的可能性很大,因此这次允许自旋等待更长时间。相反,如果某个锁对象没有被获得过,以后获得这个锁的自旋等待时间就设置的短一些。这样的自适应自旋锁很好的避免了处理器资源的浪费。

锁消除:虚拟机即时编译时候,对一些代码需要同步,但是对于被检测到的不可能进行共享数据竞争的锁进行消除。

公平锁:公平锁就是很公平的锁,每个线程按照先来后到的顺序获得锁,能保证每个线程只要等待总能获得锁。一个线程获得锁过程是,先看这个锁维护的等待队列,如果等待队列为空,或者当前想获得锁的线程是队列里的第一个,就让这个线程获得锁,否者把这个线程放到等待队列尾部,以后按照先来后到顺序,等到时候取出自己执行。

非公平锁:非公平锁就是不公平的锁,某个线程一来就开始尝试占有锁,这样可能导致某个线程占有不到锁。如果尝试失败,则把它放到队列里。执行类似于公平锁的过程。Synchronized是非公平锁,reetrantlock默认下也是非公平锁,但是在构造函数中,可以设置为公平的。

非公平锁比公平锁更能利用CPU资源,因此性能更高。但是公平锁会给业务增加可控制性。

继续阅读