java.util.concurrent.locks这个接口是关于锁的。与synchronized相比,lock更具有灵活性.
java.util.concurrent.locks的三个实现类:
- ReentrantLock
- ReentrantReadWriteLock.ReadLock
- ReentrantReadWriteLock.WriteLock
使用locks接口的三大步骤:
- 创建锁
- 加锁
- 解锁
1.创建锁
Lock lock = new ReentrantLock();
2.加锁
lock.lock();
3.解锁
lock.unlock();
Oracle官方帮助文档的代码示例:
Lock lock = ...; if (lock.tryLock()) { try { // manipulate protected state } finally { lock.unlock(); } } else { // perform alternative actions }
注意:解锁一定要放在finally{}代码块中,否则,如果try-catch有异常,就没法执行解锁语句,就死锁了。
代码演示:
重点:之前不加锁,也不加synchronized的,运行了几遍看起来没有问题,没有出现卖出0张票和票数为负数的票。
但是多运行几次就会出现某一张票被重复销售的问题。
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class LockDemo1 { public static void main(String[] args) { Ticket ticket = new Ticket(); // lambda表达式创建线程 new Thread(() -> { while (Ticket.num > 0) { ticket.sell(); } }, "A").start(); new Thread(() -> { while (Ticket.num > 0) { ticket.sell(); } }, "B").start(); new Thread(() -> { while (Ticket.num > 0) { ticket.sell(); } }, "C").start(); } } class Ticket { static int num = 50; //1.创建锁 Lock lock = new ReentrantLock(); public void sell() { //2.加锁 lock.lock(); try { Thread.sleep(2); if (num > 0) { System.out.println(Thread.currentThread().getName() + "正在卖出第" + (num--) + "张票" + "剩余票数:" + num); } } catch (Exception e) { e.printStackTrace(); } finally { //3.解锁 lock.unlock(); } } }
结果:
A正在卖出第50张票剩余票数:49 A正在卖出第49张票剩余票数:48 A正在卖出第48张票剩余票数:47 A正在卖出第47张票剩余票数:46 A正在卖出第46张票剩余票数:45 B正在卖出第45张票剩余票数:44 B正在卖出第44张票剩余票数:43 ............................................