Lock是一个接口,他有三个实现类,分别是:ReentrantLock, ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock
Lock是如何加锁的
查看jdk1.8的官方文档给出的答案:
查看源码,发现Lock默认也是非公平锁(synchronized也是非公平的):
想要设置成公平锁,那么可以在可重入锁的对象中添加一个true,会发现底层方法发生了变化:
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync();//如果是传入的参数是true,那么创建的可重入锁对象就是一个公平锁 }
简单说一些什么是公平锁和非公平锁:
公平锁: 十分公平,遵守先来后到。(一个线程先抢到CPU优先执行,直到这个线程执行完毕后,其他线程才能执行)
**非公平锁:**可以插队,根据抢夺CPU时间片来决定谁先执行。
为什么synchronized和Lock底层都是非公平的呢?
因为如果两个线程同时去执行,线程A需要3个h才能执行完,而线程B只需要3s执行完,如果是公平锁的话,线程A先执行的话,那么线程B必须等待3h后才能执行,这就大大降低了执行的效率。
举个例子,看看Lock是不是保证了我们的线程安全:
/**
* 学习Lock锁
*/
public class TestLock {
public static void main(String[] args) {
Ticket2 ticket2 = new Ticket2();
new Thread(()->{ for (int i = 0; i <30 ; i++) { ticket2.ticker(); } },"A").start();
new Thread(()->{ for (int i = 0; i <30 ; i++) { ticket2.ticker(); } },"B").start();
new Thread(()->{ for (int i = 0; i <30 ; i++) { ticket2.ticker(); } },"C").start();
new Thread().start();
}
}
class Ticket2{
private int Tick=30;
//先创建一个Lock锁对象
Lock lock=new ReentrantLock(true);//创建一个可重入锁对象
public void ticker(){
lock.lock();//开启锁
try {
//写业务方法
if (Tick>0){
System.out.println(Thread.currentThread().getName()+"已经买到了第"+ Tick-- +"张票,还剩下"+Tick+"张票");
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();//关闭可重入锁
}
}
}