JDK并发包之重入锁

锁:对共享数据加锁使其变为临界区。(排它锁)与共享锁

锁有内部锁(synchronized关键字修饰的)与显式锁(Java.concurrent.locks.Lock接口)。

显式锁与内部锁的比较

各适用环境不同,而非相互代替,内部锁申请或者释放一个锁必须在块或者同一方法中,灵活性更差,但方便,不会导致锁泄露;而显式锁可以跨方法释放锁,灵活性更高,但容易锁泄露,操作不方便,繁琐。同时显示锁支持狠多内部锁不支持的特性。

显式锁之重入锁:

重入锁存在于Java.util.concurrent.locks.ReentrantLock类。

例如:

JDK并发包之重入锁_第1张图片

之所以称为重入锁,是因为可以同一线程重复上锁,即两次上锁,两次释放锁。

中断响应:指两个线程出现死锁可以控制一方放弃申请锁,并释放已获得锁

首先营造一个死锁:


JDK并发包之重入锁_第2张图片
JDK并发包之重入锁_第3张图片
JDK并发包之重入锁_第4张图片

对于这种情况,我们能想到的办法为中断其中一个线程,即:


JDK并发包之重入锁_第5张图片

但这种方式需要在run方法中加isinterrupted作为标志位,只有为TRUE,才可中断,所以:


JDK并发包之重入锁_第6张图片
不需标志位判断

两种中断比较:


lock()加锁
JDK并发包之重入锁_第7张图片
lockInterruptibly()加锁

锁申请限时等待:

除了外部通知某个线程中断来处理死锁外,避免死锁还有另外方法:tryLock()


JDK并发包之重入锁_第8张图片
输出结果图p75

所以,对于上面的死锁问题,我们可以这样解决:


JDK并发包之重入锁_第9张图片
else同理

这样,经过几秒后,线程t1与t2都会得到锁资源并顺利执行完毕。

公平锁:

不会产生饥饿现象,synchronized不允许公平锁

说明:ReentrantLock(true)表示公平锁,其看来优美,但要实现公平锁,需要维护一个有序队列,因此公平锁实现成本高,性能低下,因此,一般情况下,锁是非公平的。如果没有特殊要求,也不推荐使用公平锁。

对于系统调度而言,一个线程更倾向于再此获得已经持有的锁,这种分配方式是高效的。

使用公平锁的结果就是,以时间片为单位,交替获得,而不公平锁大部分都是重复输出。

总结:重入锁的几个重要方法:

ReentrantLock()构造方法:实现公平非公平锁

lock():获得锁

lockInterruptibly():获得锁,但优先响应中断

tryLock():获得锁(资源),若锁被占用,返回false

tryLock(long time,TimeUnit unit):给定时间内获得锁

unlock():释放锁,千万不要忘记。

你可能感兴趣的:(JDK并发包之重入锁)