库存-并发学习笔记 (6)

非阻塞的获取锁

// 支持中断的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的变量

class SampleLock { volatile int state; // 加锁 lock() { // 省略代码无数 state = 1; } // 解锁 unlock() { // 省略代码无数 state = 0; } }

可重入锁

线程可以重复获取同一把锁

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:非公平,也就是公平竞争,容易饥饿

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygwfg.html