- 传统的 synchronized 锁
-
模拟一个卖票的场景
public class SynchronizedDemo { public static void main(String[] args) { Ticket ticket = new Ticket(); new Thread(()->{ for(int i = 0;i < 40;i++){ ticket.sale(); } },"A").start(); new Thread(()->{ for(int i = 0;i < 40;i++){ ticket.sale(); } },"B").start(); new Thread(()->{ for(int i = 0;i < 40;i++){ ticket.sale(); } },"C").start(); } } class Ticket{ //票总数 private int num = 30; public synchronized void sale(){ if(num > 0){ num--; System.out.println("当前线程:" + Thread.currentThread().getName() + "卖出了1张票,剩余" + num); } } }
2. 使用lock锁
-
位于java.util.concurrent.locks包下
-
有3个实现类
-
ReentrantLock 可重入锁
-
ReentrantReadWriteLock.ReadLock 读锁
-
ReentrantReadWriteLock.WriteLock 写锁
-
-
JAVA API文档推荐使用方式
加锁,减锁
-
使用Lock锁重写买票的例子
public class LockDemo { public static void main(String[] args) { Ticket2 ticket = new Ticket2(); new Thread(()->{ for(int i = 0;i < 40;i++)ticket.sale(); },"A").start(); new Thread(()->{ for(int i = 0;i < 40;i++)ticket.sale(); },"B").start(); new Thread(()->{ for(int i = 0;i < 40;i++)ticket.sale(); },"C").start(); } } /** * 使用Lock锁 3个步骤 * 1. new ReentrantLock(); * 2. lock.lock(); //加锁 * 3. lock.unlock(); //释放锁 */ class Ticket2{ //票总数 private int num = 30; Lock lock = new ReentrantLock(); public void sale(){ lock.lock(); //加锁 try { if (num > 0) { num--; System.out.println("当前线程:" + Thread.currentThread().getName() + "卖出了1张票,剩余" + num); } } catch (Exception e){} finally { lock.unlock(); //释放锁 } } }
-
-
关于ReentrantLock
ReentrantLock默认构造一个非公平锁
public ReentrantLock() { //构造非公平锁 sync = new NonfairSync(); }
-
Synchronized和Lock的区别
- Synchronized是一个关键字,Lock是一个类
- Synchronized会自动释放锁,在代码块执行完成或异常时。Lock需要手动释放锁,所以代码块要使用try...catch...finally包围,并在finally中释放锁。
- Synchronized无法判断锁的状态,Lock可以判断是否获取到锁
- A,B两个线程,当使用Synchronized时,B线程只能一直等待。Lock可以设置等待时间。
- Synchronized是可重入锁,不可以中断,非公平的。Lock是可重入锁,可判断锁,可设置公平性。
- Synchronized适用于少量代码块。Lock适用于大量代码块。