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
............................................
02-14 03:14