Java并发编程---显示锁和AQS(一)

前言

Java中实现并发的有两种方式,一种是锁,另外一种是CAS的原子操作。而在锁之中又分为两种,一种是Java语言层面上的内置形式(即源码中没有相关的类去实现)----Synchronized关键字,另外一种是Java源代码中有相关类进行实现的,如Lock接口。今天我们主要针对的就是后者的说明。

Lock接口和synchronized的比较:

1)synchronized: 在实现并发的代码时相对较为简洁
2)Lock: 获取锁可以被中断,可以实现超时获取锁,尝试获取锁等机制。(读多写少的情况下还可以使用读写锁)
3)Lock接口下有两个重要的接口和一个类:ReentrantLock(可重入锁), Condition, ReadWriteLock(读写锁)

1.ReentrantLock
(1)ReentrantLock(可重入锁)相当于可以获得多次同一把锁 —》(在这个层面上课以理解为Lock下synchronized的实现)
(2)可重入锁ReentrantLock, 所谓的公平和非公平锁
如果在是时间上,先对锁进行获取的请求,一定先被满足,这个锁就是公平的。如果不满足,这种锁就是非公平的。(非公平的允许插队)
(3)在可重入锁的构造函数中 ReentrantLock(boolean fair) 其中参数值fair用来表示公平锁和非公平锁,缺省情况下为非公平的。
一般来说,非公平锁的效率相对较高。(why?)
下面举个简单的例子:线程A和线程B运行过程中,线程A先获得了锁,此时线程B处于挂起状态,在线程B挂起阶段中,线程C被创建并处于活跃状态,此时线程A释放锁后,线程C可以直接获得锁,假设线程C释放锁时,线程B刚好从挂起到就绪,并获得释放的锁,这时运行效率相对公平锁的到了提高。
(4) ReentrantLock和synchronized关键字都是排他锁(同一时刻只允许一个线程进行访问)

2.ReadWriteLock接口和读写锁ReentrantReadWriteLock:
(1)读写锁:同一时刻,允许运行多个读线程同时访问,但是写线程访问的时候所有的读和写线程都会被阻塞,最适用于读多写少的情况下。
基于以上机制,ReentrantReadWriteLock中读写锁的升降级:
允许写锁降级为读锁,但不允许读锁升级为写锁。
可降级的原因:读锁是阻塞写锁的,只有读锁都释放以后,写锁才能获得。这时所用的线程都可看到写入的东西。
不可升级的原因:当同时有线程获得了读锁和写锁时,获得读锁的线程可能看不到写锁写入的内容。
(2)理解ReentrantReadWriteLock实现:
与可重入锁不同的是读写锁有两种不同的状态即读锁和写锁,(在可重入锁中只需要设置一个state状态就可以对锁进行控制)那么读写锁又是如何表现不同锁的状态的呢?
a.读写状态的设置是由一个32字节的state切成两半进行划分的,高16位用来保存读状态。低16位用来保存写状态。
b.每个读线程重入的此时是由一个线程的局部变量ThreadLocalHoldCounter来保存每一个锁重入的数量。

3.Condition接口 (可以理解为synchronized下的等待通知模式)
(1)用Lock 和 Condition实现等待通知 (其中Condition接口下的await()方法类似于Synchronized中Object方法下的wait() )
通知的方法: singal() 类似于 notify() singalAll()类似于notifyAll()
(2)一个Lock可以new出多个Condition

4. 了解LockSupport工具:
(1)作用:阻塞一个线程和唤醒一个线程
(2) park 开头的方法表示阻塞
unpark(Thread thread): 方法表示唤醒

发布了19 篇原创文章 · 获赞 2 · 访问量 417

猜你喜欢

转载自blog.csdn.net/TheWindOfSon/article/details/103881116