非阻塞的获取锁
// 支持中断的API void lockInterruptibly() throws InterruptedException; // 支持超时的API boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 支持非阻塞获取锁的API boolean tryLock();如何保证可见性
synchronized
happens-before中有一个锁规则,保证了synchronized的可见性
Lock
利用了 volatile 相关的 Happens-Before 规则
ReentrantLock 内部持有一个volatile的变量
可重入锁
线程可以重复获取同一把锁
ReentrantLock汉语意思就是可重入锁的含义
公平锁与非公平锁
公平锁:按照先来先得的原则,完全公平。其实就是排队等待
非公平锁:公平竞争锁,每次竞争所有线程获取锁的机会是均等待。(为什么叫非公平锁呢?因为运气不好的可能造成线程饥饿)
15 | Lock和Condition(下):Dubbo如何用管程实现异步转同步?笔记
相对synchronized + wait + notify/ReentrantLock + Condition的优势
Lock&Condition 实现的管程是支持多个条件变量的,这是二者的一个重要区别。
sync + wait只能支持一个条件,因为条件都是绑定到monitor上的,每一个锁只有一个monitor
如何实现一个阻塞队列
阻塞队列需要两个条件:满阻塞/空阻塞
sync管程只能实现一个阻塞,因为其只能支持一个条件变量
lock + Condition 可以支持多个条件变量
复习
sync + wait + notify + notifyAll
lock + Condition + await + signal + signalAll
public class BlockedQueue<T>{ final Lock lock = new ReentrantLock(); // 条件变量:队列不满 final Condition notFull = lock.newCondition(); // 条件变量:队列不空 final Condition notEmpty = lock.newCondition(); // 入队 void enq(T x) { lock.lock(); try { while (队列已满){ // 等待队列不满 notFull.await(); } // 省略入队操作... //入队后,通知可出队 notEmpty.signal(); }finally { lock.unlock(); } } // 出队 void deq(){ lock.lock(); try { while (队列已空){ // 等待队列不空 notEmpty.await(); } // 省略出队操作... //出队后,通知可入队 notFull.signal(); }finally { lock.unlock(); } } }Dubbo如何实现异步的RPC实现同步的等待结果// 创建锁与条件变量 private final Lock lock = new ReentrantLock(); private final Condition done = lock.newCondition(); // 调用方通过该方法等待结果 Object get(int timeout){ long start = System.nanoTime(); lock.lock(); try { while (!isDone()) { done.await(timeout); long cur=System.nanoTime(); if (isDone() || cur-start > timeout){ break; } } } finally { lock.unlock(); } if (!isDone()) { throw new TimeoutException(); } return returnFromResponse(); } // RPC结果是否已经返回 boolean isDone() { return response != null; } // RPC结果返回时调用该方法 private void doReceived(Response res) { lock.lock(); try { response = res; if (done != null) { done.signal(); } } finally { lock.unlock(); } }
猜想
Future应该也是通过 Lock + Condition实现的
明天看源码ArrayListBlockQueue/LinkedListBlockQueue,看二者如何实现的阻塞
16 | Semaphore:如何快速实现一个限流器?笔记
信号量
互斥性
Semaphore如何实现互斥。指定Semaphore的计数器为1,也就意味着同一个时刻只能有一个线程可以访问临界区资源
线程并行控制
Semaphore如何控制并发。Semaphore通过计数器,控制访问临界区的线程不能超过计数器值。
操作系统中也存在信号量--作用和java中的信号量也是相同的
操作系统利用信号量控制进程的并行
Semaphore 的公平性
默认Semaphore是非公平的,同 ReentrantLock
Semaphore提供了两个构造方法,如下所示,两个参数的构造方法,第二个参数可以指定公平性
false:非公平,也就是公平竞争,容易饥饿