ReentrantLock重入锁
使用ReentrantLock可以完成和synchronized同样的功能,但是使用synchronized可以自动释放锁,使用重入锁必须要手动释放锁,所以一般会放在finally块中释放锁。
尝试锁定
使用ReentrantLock可以进行尝试锁定,这样在无法锁定或者在指定时间内无法锁定,线程可以决定是否继续等待。在尝试锁定之后,不管有没有锁定,方法都将继续执行。所以,可以在方法中根据是否锁定来进行相应的逻辑处理。
获取不到锁可被interrupt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| public class Lock02 {
Lock lock = new ReentrantLock();
void m1 () { try { lock.lock(); System.out.println("t1 start"); TimeUnit.SECONDS.sleep(Integer.MAX_VALUE); System.out.println("t1 end"); } catch (InterruptedException e) { System.out.println("t1 interrupted"); } finally { lock.unlock(); } }
void m2() { boolean isLock = false; try {
lock.lockInterruptibly(); isLock = lock.tryLock(); System.out.println("t2 start"); TimeUnit.SECONDS.sleep(5); System.out.println("t2 end"); } catch (Exception e) { System.out.println("t2 interrupted"); } finally { if (isLock) { lock.unlock(); }
} }
public static void main(String[] args) { Lock02 lock01 = new Lock02(); Thread t1 = new Thread(new Runnable() { @Override public void run() { lock01.m1(); } }); t1.start();
Thread t2 = new Thread(new Runnable() { @Override public void run() { lock01.m2(); } });
t2.start();
try { TimeUnit.SECONDS.sleep(1L); } catch (InterruptedException e) { e.printStackTrace(); } t2.interrupt(); }
}
|
线程t1在Integer.MAX_VALUE的时间内会一直执行,正常情况下t2是获取不到锁的,这个时候如果不做处理,那么t2将会一直等待下去,不会被其他线程打断。但是如果在t2中调用了lock.lockInterruptibly();方法之后,则表明t2是可以被打断的。也就是说,t2在等待t1释放锁的过程中,如果不想继续等了,主线程调用t2.interrupt()方法即可将t2线程打断。
指定为公平锁
假如现在有6个线程,其中一个线程拿到了锁顺利执行完逻辑后释放了锁,这时候剩下的5个线程都会去争用这把锁,谁先拿到就是谁的,谁就可以执行,并不会关心其他的线程等了多长的时间,也就是说不会根据谁等的时间长,谁就优先获得锁。这种称为竞争锁,不是公平锁。这种的效率会高些,因为线程调度器不用计算哪个线程等待的时间更长。synchronized默认是非公平锁。
公平锁自然就是根据等待时间来判断谁可以先获取到锁的。new ReentrantLock(true)即可声明为公平锁。