Java锁机制- - 草稿 - 草稿

可重入锁、可中断锁、公平锁、读写锁、自旋锁。

锁的相关概念介绍

1、可重入锁

如果锁具有可重入性,则称为可重入锁,synchronized和reentranLoke都是可重入锁。可重入性在我看来是表明了锁的分配机制,基于线程的分配,而不是基于方法调用的分配。比如说当一个线程执行到某个synchronized方法method1时,在方法method1内部又调用了另一个synchronized方法method2,此时线程不必重新申请锁,而是可以直接执行方法method2。

假如synchronized锁不具备可重入性,当线程执行到synchronized方法method1中的synchronized方法method2时,线程会尝试获取锁,由于synchronized锁是这个线程本身持有的,此时线程就会陷入一种等待自身释放锁的无限等待中。

由于synchronized锁和lock锁都具有可重入性,所以就不会出现上述情况。

2、可中断锁

顾名思义,就是可以执行中断操作的锁。

在java中,synchronized是不可中断锁,而lock是可中断锁。

如果某一线程在执行获取锁的过程中等待的时间过长,此时这个线程不想等待了,我们可以让这个线程本身中断等待或者让另一线程来中断等待,这种可以被中断的锁就是可中断锁。

3、公平锁

公平锁就是尽量以公平的方式来获取锁,比如当一个锁被释放时,等待时间最久(最先申请锁)的那个线程会获得该锁,这就是公平锁。

非公平锁就是无法保证锁的获取是按照请求顺序进行的,这样就可能导致某个或某些线程永远获取不到锁。

在Java中,synchronized锁是非公平锁,它无法保证等待的线程获取锁的顺序。

reentrantlock锁和reentrantReadWirteLock锁,他们默认情况下是非公平锁,但是可以设置为公平锁。

reentrantlock类中定义了2个静态内部类,NotFairSync和FairSync,分别原来实现非公平锁和公平锁。我们可以在创建ReentrantLock对象时,来设置锁的公平性。

给构造函数传入true为公平锁,传入false为非公平锁。不穿默认情况下为非公平锁。

ReentrantReadWirteLock中也有类似的方法,不过ReentrantReadWirteLock并没有实现lock接口,而是实现了ReadWirteLock接口。

4、读写锁

读写锁将对一个资源的访问分为2个锁,即一个读锁,一个写锁。

正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。

ReadWirteLock就是读写锁,它是一个接口,ReentrantReadWirteLock实现了这个接口。

可以通过readLock()获取读锁,通过wirteLock()获取写锁。

5、自旋锁

首先是一种锁,与互斥锁相似,基本作用是用于线程之间的同步。与普通锁不同的是,一个线程A在获得普通锁后,如果再有其他线程B来试图获取锁,那么这个线程B将会挂起(阻塞);试想下,如果2个线程资源竞争不是很激烈,而处理器阻塞一个线程引起的线程上下文切换的代价可能高于线程等待资源代价的时候,那么线程B可以不放弃cpu时间片,而是在原地忙等,直到锁的持有线程释放了这个锁。这就是自旋锁的原理,可见自旋锁是一种非阻塞锁。

自旋锁可能引起的问题?

1.过多占据cpu时间:如果锁的持有者长时间不释放该锁,那么等待线程将会长时间的占据cpu的时间片,导致cpu资源浪费,因此,可以设定一个时间,若超过这个时间,锁还未释放,那么等待者放弃cpu时间片进入阻塞。

2.死锁问题:有一个线程连续2次试图获得自旋锁,当第一次获得自旋锁后,改线程又试图获取自旋锁,此时检测到锁被占用(其实是被自己占用),那么这时,该线程会一直等待自己释放改锁,而不能继续执行,这样就引起了死锁。因此,使用自旋锁时程序绝不能在持有自旋锁时调用它自己,也绝不能在递归调用时试图获取相同的自旋锁。


6、乐观锁/悲观锁

乐观锁与悲观锁不是具体什么类型的锁,而是指看待并发同步的角度。

悲观锁认为对于同一个数据的并发操作,一定是会发生修改的,哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁的操作一定会出问题的。

乐观锁则认为对同一个数据的并发操作,是不会发生修改的。在更新数据的时候,会采用尝试更新,不断重新的方式来更新数据。乐观的认为,不加锁的并发操作是没有事情的。

从上述我们可以看出,悲观锁适合写操作非常多的场景,乐观锁适合读操作非常多的场景,不加锁会带来大量的性能提升。

悲观锁在java中的使用,就是利用各种锁。

乐观锁在java中的使用,就是无锁编程,常常采用的是CAS算法,典型的例子就是原子类,通过CAS自旋实现原子操作的更新。

7、偏向锁/轻量级锁/重量级锁

这3种锁是指锁的状态,并且是针对synchronized锁。在java5通过锁升级机制来实现高性能synchronized。这3月种锁的状态是通过对象监视器在对象头中的字段来表明的。

偏向锁是指一段同步代码块一直被同一个线程访问,那么该线程会自动获取锁,降低获取锁的代价。

轻量级锁是指当锁为偏向锁的时候,被另一个线程访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的方式来获取锁,不会阻塞,提高性能。

重量级锁是指当锁为轻量级锁的时候,另一个线程虽然为自旋,但自旋不会一直持续下去,当自旋到一定次数之后,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,降低性能。

你可能感兴趣的:(Java锁机制- - 草稿 - 草稿)