通过查看 Lock 的源码可知,Lock是一个接口。Lock有一个实现类 ReentrantLock
1public interface Lock {
2 void lock();//获得锁,如果锁已经被占用,则等待
3
4 void lockInterruptibly() throws InterruptedException;//获得锁,但优先响应中断
5
6 boolean tryLock();// 尝试获得锁,如果成功,返回true,失败返回false。该方法不等待,立即返回
7
8 boolean tryLock(long time, TimeUnit unit) throws InterruptedException; // 在给定时间内尝试获得锁
9
10 void unlock(); //用来释放锁
11
12 Condition newCondition();
13}
Lock方法
场景:如果发现该操作已经在执行,等待一个一个执行(同步执行,类似synchronized)
1public class Lockone implements Runnable{
2 public static ReentrantLock lock=new ReentrantLock();
3 @Override
4 public void run() {
5 try{
6 lock.lock();
7 } finally {
8 lock.unlock();
9 }
10
11 }
12 public static void main(String[] args) {
13 Lockone Lock=new Lockone();
14 Thread t1=new Thread(Lock);
15 Thread t2=new Thread(Lock);
16 t1.start();
17 t2.start();
18 }
19}
lockInterruptibly
场景:如果发现该操作已经在执行,等待执行。这时可中断正在进行的操作立刻释放锁继续下一操作
- 什么是中断响应?
对于synchronized来说,如果一个线程在等待锁,那么结果只有两种,要么它获得这把锁继续执行,要么它就保持等待。而重入锁,则提供另一种可能,那就是线程可以被中断。也就是在等待锁的过程中,程序可以根据需要取消对锁的请求。中断正式提供了一套类似机制,如果一个线程正在等待锁,那么他依然可以接到一个通知,被告知,无需在等待,可以停止工作了。
举个例子:
1public class LockInter implements Runnable{
2 public static ReentrantLock lock=new ReentrantLock(true);
3 @Override
4 public void run() {
5 try {
6 //lock.lockInterruptibly();
7 lock.lock();
8 System.out.println(Thread.currentThread().getName()+"running");
9 Thread.sleep(5000);
10 lock.unlock();
11 System.out.println(Thread.currentThread().getName()+" finished");
12 } catch (InterruptedException e) {
13 System.out.println(Thread.currentThread().getName()+" interrupted");
14 }
15
16 }
17 public static void main(String[] args) {
18 LockInter mm=new LockInter();
19 Thread t1=new Thread(mm);
20 Thread t2=new Thread(mm);
21 t1.start();
22 t2.start();
23 t2.interrupt();
24 }
25
26
27}
6运行的结果是
1Thread-0running
2Thread-1 interrupted
3Thread-0 finished
7运行的结果是
1Thread-0running
2Thread-0 finished
3Thread-1running
4Thread-1 interrupted
看出差别来了嘛。lock方法比较死板,必须得等当前线程结束,才会响应其他线程的中断
tryLock
场景:如果发现该操作已经在执行中则不再执行(有状态执行)
有返回值,它表示用来尝试获取锁,如果获取成功返回true;如果获取失败(即锁已被其他线程获取),则返回失败
1import java.util.concurrent.TimeUnit;
2import java.util.concurrent.locks.ReentrantLock;
3
4public class TimeLock implements Runnable{
5 public static ReentrantLock lock=new ReentrantLock();
6
7 @Override
8 public void run() {
9 try {
10 if(lock.tryLock(5, TimeUnit.SECONDS)){
11 Thread.sleep(6000);
12 }else{
13 System.out.println("获取失败");
14 }
15 } catch (InterruptedException e) {
16 e.printStackTrace();
17 }finally {
18 if (lock.isHeldByCurrentThread()) {
19 lock.unlock();
20 }
21 }
22 }
23 public static void main(String[] args) {
24 TimeLock timeLock=new TimeLock();
25 Thread t1=new Thread(timeLock);
26 Thread t2=new Thread(timeLock);
27 t1.start();
28 t2.start();
29 }
30}
isHeldByCurrentThread() 查询当前线程是否保持锁定
trylock()两个参数第一个是等待时长,第二个表示计时单位
运行结果:
1获取失败
公平锁和非公平锁
- 公平锁是指多个线程等待同一个锁时,必须按照申请锁的先后顺序来一次获得锁
特点:等待锁的线程不会饿死,但整体效率相对低一些 - 非公平锁是指可以不按照顺序,可以抢占锁
特点:整体效率高,但有些线程会饿死或者说很早就在等待锁,但要等很久才会获得锁
重入锁有这样一个构造函数,对公平性进行设置。当fair为true时,表示此锁是公平的
1public ReentrantLock(boolean fair) {
2 sync = fair ? new FairSync() : new NonfairSync();
3 }
举个公平锁的例子:
1import java.util.concurrent.locks.ReentrantLock;
2
3public class FairLock implements Runnable{
4 public static ReentrantLock lock=new ReentrantLock(true);
5 @Override
6 public void run() {
7 while (true) {
8 try {
9 lock.lock();
10 System.out.println(Thread.currentThread().getName()+"获得锁");
11 } finally {
12 lock.unlock();
13 }
14 }
15 }
16 public static void main(String[] args) {
17 FairLock fairLock=new FairLock();
18 Thread t1=new Thread(fairLock);
19 Thread t2=new Thread(fairLock);
20 t1.start();
21 t2.start();
22 }
23}
运行结果
1Thread-0获得锁
2Thread-1获得锁
3Thread-0获得锁
4Thread-1获得锁 //只截取一部分,但可以看出线程是按照顺序执行
newCondition
下回分解