JUC——线程同步锁(ReentrantLock)
ReentrantLock简介
ReentrantLock是一个可重复的互斥锁,又被称为独占锁,可重入的意思是:ReentrantLock锁可以被单个线程多次获取。但是在同一个时间点只能被一个线程锁持有
ReentrantLock使用一个FIFO(先进先出)的等待队里来管理获取该锁所有线程的。
ReentrantLock是一个独占锁,在获取锁的之后其所有的操作都是线程独享的,其他的线程在没有获取到锁之前都需要等待。
public class ReentrantLock implements Lock,java.io.Serializable
ReentrantLock之中分为公平锁与非公平锁,它们的区别体现在获取锁的机制上是否公平以及执行速度上。、
这两种锁的启用也是非常容易控制的,这个类提供的构造方法如下:
- 无参构造(非公平锁,NonfairSync)
public ReentrantLock() { sync = new NonfairSync(); }
- 有参构造
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
//fair = true,表示公平锁,FairSync
//fair = false,表示非公平锁,NonfairSync
ReentrantLock继承结构
范例:使用ReentrantLock定义一个多线程卖票的处理程序
package so.strong.mall.concurrent; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class Ticket { private Lock myLock = new ReentrantLock(); //非公平锁 private int count = 10; //一共10张票 public void sale() { myLock.lock(); //进入到阻塞状态,一直到unlock执行后解除阻塞 try { if (this.count > 0) { System.out.println(Thread.currentThread().getName() + "卖票,ticket=" + this.count--); } } finally { myLock.unlock(); //不管最终结果如何一定要进行解锁 } } } public class TestDemo { public static void main(String[] args) { final Ticket ticket = new Ticket(); //多线程要共享同一个数据资源 for (int i = 0; i < 6; i++) { new Thread(new Runnable() { @Override public void run() { while (true) { ticket.sale(); //卖票处理 } } }).start(); } } }
Thread-0卖票,ticket=10 Thread-0卖票,ticket=9 Thread-0卖票,ticket=8 Thread-0卖票,ticket=7 Thread-0卖票,ticket=6 Thread-0卖票,ticket=5 Thread-0卖票,ticket=4 Thread-2卖票,ticket=3 Thread-2卖票,ticket=2 Thread-2卖票,ticket=1
当前的代码要比直接使用synchronized更加容易,而且锁的处理机制更加的直观。通过查看源代码可以发现,使用lock()进行锁定的时候会考虑两种情况:
Sync-java.util.concurrent.locks.ReentrantLock
- FairSync-java.util.concurrent.locks.ReentrantLock
- NonFairSync-java.util.concurrent.locks.ReentrantLock
在进行公平锁处理的时候每当锁定一个线程对象就会使用“acquire(1)”方法进行表示:
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
在进行解锁时会使用一个"sync.release(1)”释放方法, 1 表示释放一个:
public void unlock() { sync.release(1); }