Java并发编程札记-(四)JUC锁-02Lock与ReentrantLock
2017-12-09 23:50
274 查看
今天学习Lock与ReentrantLock。
Java中的锁有两种,synchronized与Lock。因为使用synchronized并不需要显示地加锁与解锁,所以往往称synchronized为隐式锁,而使用Lock时则相反,所以一般称Lock为显示锁。想了解synchronized更多请移步Java并发编程札记-(一)基础-06synchronized详解。
synchronized修饰方法或语句块,所有锁的获取和释放都必须出现在一个块结构中。当需要灵活地获取或释放锁时,synchronized显然是不符合要求的。Lock接口的实现允许锁在不同的范围内获取和释放,并支持以任何顺序获取和释放多个锁。
一句话,Lock实现比synchronized更灵活。但凡事有利就有弊,不使用块结构锁就失去了使用synchronized修饰方法或语句时会出现的锁自动释放功能,在大多数情况下,Lock实现需要手动释放锁。
除了更灵活之外,Lock还有以下优点:
Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。
Lock 类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。
ReentrantLock是一个可重入的互斥锁。顾名思义,“互斥锁”表示在某一时间点只能被同一线程所拥有。“可重入”表示锁可被某一线程多次获取。
当锁没有被某一线程占有时,调用lock()方法的线程将成功获取锁。可以使用isHeldByCurrentThread()和 getHoldCount()方法来判断当前线程是否拥有该锁。
ReentrantLock既可以是公平锁又可以是非公平锁。当此类的构造方法ReentrantLock(boolean fair) 接收true作为参数时,ReentrantLock就是公平锁,线程依次排队获取公平锁,即锁将被等待最长时间的线程占有。与默认情况(使用非公平锁)相比,使用公平锁的程序在多线程环境下效率比较低。而且公平锁不能保证线程调度的公平性,tryLock方法可在锁未被其他线程占用的情况下获得该锁。
方法列表
使用最典型的代码如下
修改下Java并发编程札记-(一)基础-06synchronized详解中火车票订票系统实例,使用ReentrantLock实现线程安全。
例6:火车票订票系统-ReentrantLock实现线程安全版
在某些方法的参数中出现了Condition,在后面我们会详细介绍Condition。
总结
与synchronized 相比ReentrantLock的使用更灵活。Lock接口的实现允许锁在不同的范围内获取和释放,并支持以任何顺序获取和释放多个锁。
ReentrantLock具有与使用 synchronized 相同的一些基本行为和语义,但功能更强大。包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。
ReentrantLock具有synchronized所没有的许多特性,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者轮询锁。
ReentrantLock可伸缩性强,应当在高度争用的情况下使用它。
本文就讲到这里,想了解Java并发编程更多内容请参考:
Java并发编程札记-目录
参考:
JDK 5.0 中更灵活、更具可伸缩性的锁定机制
END.
Java中的锁有两种,synchronized与Lock。因为使用synchronized并不需要显示地加锁与解锁,所以往往称synchronized为隐式锁,而使用Lock时则相反,所以一般称Lock为显示锁。想了解synchronized更多请移步Java并发编程札记-(一)基础-06synchronized详解。
synchronized修饰方法或语句块,所有锁的获取和释放都必须出现在一个块结构中。当需要灵活地获取或释放锁时,synchronized显然是不符合要求的。Lock接口的实现允许锁在不同的范围内获取和释放,并支持以任何顺序获取和释放多个锁。
一句话,Lock实现比synchronized更灵活。但凡事有利就有弊,不使用块结构锁就失去了使用synchronized修饰方法或语句时会出现的锁自动释放功能,在大多数情况下,Lock实现需要手动释放锁。
除了更灵活之外,Lock还有以下优点:
Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。
Lock 类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录。
ReentrantLock是一个可重入的互斥锁。顾名思义,“互斥锁”表示在某一时间点只能被同一线程所拥有。“可重入”表示锁可被某一线程多次获取。
当锁没有被某一线程占有时,调用lock()方法的线程将成功获取锁。可以使用isHeldByCurrentThread()和 getHoldCount()方法来判断当前线程是否拥有该锁。
ReentrantLock既可以是公平锁又可以是非公平锁。当此类的构造方法ReentrantLock(boolean fair) 接收true作为参数时,ReentrantLock就是公平锁,线程依次排队获取公平锁,即锁将被等待最长时间的线程占有。与默认情况(使用非公平锁)相比,使用公平锁的程序在多线程环境下效率比较低。而且公平锁不能保证线程调度的公平性,tryLock方法可在锁未被其他线程占用的情况下获得该锁。
方法列表
//构造方法摘要 ReentrantLock() //创建一个 ReentrantLock 的实例。 ReentrantLock(boolean fair) //创建一个具有给定公平策略的 ReentrantLock。 //方法摘要 int getHoldCount() //查询当前线程保持此锁的次数。 protected Thread getOwner() //返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null。 protected Collection<Thread> getQueuedThreads() //返回一个 collection,它包含可能正等待获取此锁的线程。 int getQueueLength() //返回正等待获取此锁的线程估计数。 protected Collection<Thread> getWaitingThreads(Condition condition) //返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。 int getWaitQueueLength(Condition condition) //返回等待与此锁相关的给定条件的线程估计数。 boolean hasQueuedThread(Thread thread) //查询给定线程是否正在等待获取此锁。 boolean hasQueuedThreads() //查询是否有些线程正在等待获取此锁。 boolean hasWaiters(Condition condition) //查询是否有些线程正在等待与此锁有关的给定条件。 boolean isFair() //如果此锁的公平设置为 true,则返回 true。 boolean isHeldByCurrentThread() //查询当前线程是否保持此锁。 boolean isLocked() //查询此锁是否由任意线程保持。 void lock() //获取锁。 void lockInterruptibly() //如果当前线程未被中断,则获取锁。 Condition newCondition() //返回用来与此 Lock 实例一起使用的 Condition 实例。 String toString() //返回标识此锁及其锁定状态的字符串。 boolean tryLock() //仅在调用时锁未被另一个线程保持的情况下,才获取该锁。 boolean tryLock(long timeout, TimeUnit unit) //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。 void unlock() //试图释放此锁。
使用最典型的代码如下
class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }
修改下Java并发编程札记-(一)基础-06synchronized详解中火车票订票系统实例,使用ReentrantLock实现线程安全。
例6:火车票订票系统-ReentrantLock实现线程安全版
import java.util.concurrent.locks.ReentrantLock; public class SellTickets { public static void main(String[] args) { TicketsWindow tw1 = new TicketsWindow(); Thread t1 = new Thread(tw1, "一号窗口"); Thread t2 = new Thread(tw1, "二号窗口"); t1.start(); t2.start(); } } class TicketsWindow implements Runnable { private int tickets = 1; private final ReentrantLock lock = new ReentrantLock(); @Override public void run() { while (true) { lock.lock(); try { if (tickets > 0) { System.out.println(Thread.currentThread().getName() + "还剩余票:" + tickets + "张"); --tickets; System.out.println(Thread.currentThread().getName() + "卖出一张火车票,还剩" + tickets + "张"); } else { System.out.println(Thread.currentThread().getName() + "余票不足,暂停出售!"); try { Thread.sleep(1000 * 60); } catch (InterruptedException e) { e.printStackTrace(); } } } finally { lock.unlock(); } } } }
在某些方法的参数中出现了Condition,在后面我们会详细介绍Condition。
总结
与synchronized 相比ReentrantLock的使用更灵活。Lock接口的实现允许锁在不同的范围内获取和释放,并支持以任何顺序获取和释放多个锁。
ReentrantLock具有与使用 synchronized 相同的一些基本行为和语义,但功能更强大。包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。
ReentrantLock具有synchronized所没有的许多特性,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者轮询锁。
ReentrantLock可伸缩性强,应当在高度争用的情况下使用它。
本文就讲到这里,想了解Java并发编程更多内容请参考:
Java并发编程札记-目录
参考:
JDK 5.0 中更灵活、更具可伸缩性的锁定机制
END.
相关文章推荐
- 详解JUC之锁——Lock与AQS(02)
- JUC中Lock和ReentrantLock介绍及源码解析
- (三)juc高级特性——虚假唤醒 / Condition / 按序交替 / ReadWriteLock / 线程八锁
- 【JDK1.8】JUC——ReentrantLock
- JUC-007-同步锁Lock
- java并发-ReentrantLock的lock和lockInterruptibly的区别
- Java之JUC系列(02)--锁机制
- JUC锁-02之 互斥锁ReentrantLock
- JUC集合-02之 CopyOnWriteArrayList
- ReentrantLock代码剖析之ReentrantLock.unlock
- Java多线程系列--【JUC集合02】- CopyOnWriteArrayList
- Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock
- 《深入浅出 Java Concurrency》—锁机制(一)Lock与ReentrantLock
- Java多线程系列--“JUC原子类”02之 AtomicLong原子类 (r)
- JUC - ReentrantReadWriteLock 源码分析
- Java并发编程札记-(五)JUC容器-05ArrayBlockingQueue与LinkedBlockingQueue
- Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock
- java多线程系类:JUC线程池:02之线程池原理(一)
- JUC之ReentrantReadWriteLock(JDK1.8源码)
- 第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()