JUC - Lock接口
程序员文章站
2022-05-05 16:34:20
...
Lock接口详解:
-
什么是Lock :
-
为什么要使用Lock:(不是已经有了synchronized了?)
- Java中的锁有两种,synchronized与Lock。因为使用synchronized并不需要显示地加锁与解锁,所以往往称synchronized为隐式锁,而使用Lock时则相反,所以一般称Lock为显示锁 也就是需要手动的进行加锁和 释放锁
- synchronized修饰方法或语句块,所有锁的获取和释放都必须出现在一个块结构中。当需要灵活地获取或释放锁时,synchronized显然是不符合要求的。Lock接口的实现允许锁在不同的范围内获取和释放,并支持以任何顺序获取和释放多个锁
- Lock 实现提供了使用 synchronized 方法和语句所没有的其他功能,包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。
- Lock 类还可以提供与隐式监视器锁完全不同的行为和语义,如保证排序、非重入用法或死锁检测。如果某个实现提供了这样特殊的语义,则该实现必须对这些语义加以记录
- 总结起来就是一句话 Lock实现比synchronized更灵活 能够以更加面向对象的方式实现锁
-
Lock锁的使用:
-
多线程经典问题就是买票问题:以往都是使用synchronized进行实现的 :(30张票 3个线程售票 防止超卖 使用synchronized 比较的简单)
class Ticket { private int number = 30; public synchronized void sale() { synchronized (this) { if (number > 0) { System.out.println(Thread.currentThread().getName() + "\t 卖出" + number-- + "号票\t还剩" + number); } } } }
public static void main(String[] args) throws Exception { Ticket ticket = new Ticket(); new Thread(()->{for (int i = 1; i <= 40; i++) ticket.saleBySync(); },"AA").start(); new Thread(()->{for (int i = 1; i <= 40; i++) ticket.saleBySync(); },"BB").start(); new Thread(()->{for (int i = 1; i <= 40; i++) ticket.saleBySync(); },"CC").start(); }
-
另一种形式Lock(需要手动的进行加锁 和 锁的释放)
private Lock lock = new ReentrantLock(); public void saleByLock() { lock.lock(); try { if (number > 0) { System.out.println(Thread.currentThread().getName() + "\t 卖出" + number-- + "号票\t还剩" + number ); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }
-
-
ReentrantLock详解:
-
ReentrantLock是一个可重入的互斥锁。顾名思义,“互斥锁”表示在某一时间点只能被同一线程所拥有。“可重入”表示锁可被某一线程多次获取 当锁没有被某一线程占有时,调用lock()方法的线程将成功获取锁。可以使用
isHeldByCurrentThread()
和getHoldCount()
方法来判断当前线程是否拥有该锁。 -
ReentrantLock既可以是公平锁又可以是非公平锁。当此类的构造方法
ReentrantLock(boolean fair)
接收true作为参数时,ReentrantLock就是公平锁,线程依次排队获取公平锁,即锁将被等待最长时间的线程占有。与默认情况(使用非公平锁)相比,使用公平锁的程序在多线程环境下效率比较低。而且公平锁不能保证线程调度的公平性,tryLock方法可在锁未被其他线程占用的情况下获得该锁 -
Lock使用:
class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }
-
5.总结
- 与synchronized 相比ReentrantLock的使用更灵活。Lock接口的实现允许锁在不同的范围内获取和释放,并支持以任何顺序获取和释放多个锁。
- ReentrantLock具有与使用 synchronized 相同的一些基本行为和语义,但功能更强大。包括提供了一个非块结构的获取锁尝试 (tryLock())、一个获取可中断锁的尝试 (lockInterruptibly()) 和一个获取超时失效锁的尝试 (tryLock(long, TimeUnit))。
- ReentrantLock具有synchronized所没有的许多特性,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者轮询锁。
- ReentrantLock可伸缩性强,应当在高度争用的情况下使用它
上一篇: WEB应用开发设计实验报告四
下一篇: 多线程——线程的运行状态