1、lock()
首先在让thread1获取到锁并开始执行逻辑,此时thread2调用lock()会阻塞等待锁,在最后调用thread.inerrupt()尝试中断线程,发现没有效果,详看下方输出值
public class LockTest {
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
Thread thread1 = new Thread(() -> {
lock.lock();
System.out.println("thread1:得到锁");
//死循环
for (int i = 0; i < 3; i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("thread1:释放锁");
lock.unlock();
});
Thread thread2 = new Thread(() -> {
try {
lock.lock();
System.out.println("thread2:得到锁");
}
finally {
try {
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("thread2:释放锁");
});
thread1.start();
//让thread1先执行
Thread.sleep(50);
thread2.start();
//主线程阻塞一会让所有子线程启动
Thread.sleep(100);
//中断线程2
thread2.interrupt();
}
}
输出值如下,在thread1业务执行完毕后,thread2正常获得锁
thread1:得到锁
0
1
2
thread1:释放锁
thread2:得到锁
thread2:释放锁
2、lockInterruptibly()
代码与lock()的测试代码类似,重点把thread2中调用lock()改成了lockInterruptibly()并catch异常InterruptedException(受检异常,必须catch)
public class LockInterruptiblyTest {
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
Thread thread1 = new Thread(() -> {
lock.lock();
System.out.println("thread1:得到锁");
//死循环
for (int i = 0; i < 3; i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();
System.out.println("thread1:释放锁");
});
Thread thread2 = new Thread(() -> {
try {
//改动点
lock.lockInterruptibly();
System.out.println("thread2:得到锁");
//捕获中断异常
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
try {
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("thread2:中断结束");
});
thread1.start();
//让thread1先执行
Thread.sleep(100);
thread2.start();
//主线程组合一会让子线程启动
Thread.sleep(100);
thread2.interrupt();
}
}
输出如下,可见thread2提前放弃了获取锁并结束了
InterruptedException:捕获的是thread2线程中断的异常
IllegalMonitorStateException:捕获的是unlock()方法的异常,因为没有获得锁的时候,不能释放锁
thread1:得到锁
0
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at com.calulator.LockInterruptiblyTest.lambda$main$1(LockInterruptiblyTest.java:27)
at java.lang.Thread.run(Thread.java:748)
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at com.calulator.LockInterruptiblyTest.lambda$main$1(LockInterruptiblyTest.java:34)
at java.lang.Thread.run(Thread.java:748)
thread2:中断结束
1
2
thread1:释放锁
3、tryLock()
tryLock()和lock()方法类似,只是再获取不到锁时不阻塞,返回false,若是成功获取锁则返回true。和lock()类似,调用interrupt()无法中断线程
public class TryLockTest {
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
Thread thread1 = new Thread(() -> {
lock.tryLock();
System.out.println("thread1:得到锁");
//死循环
for (int i = 0; i < 3; i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("thread1:释放锁");
lock.unlock();
});
Thread thread2 = new Thread(() -> {
boolean alreadyLock = false;
try {
alreadyLock = lock.tryLock();
if (alreadyLock)
System.out.println("thread2:得到锁");
}
catch (Exception e){
e.printStackTrace();
}
finally {
if (alreadyLock){
lock.unlock();
}
}
System.out.println("thread2:结束");
});
thread1.start();
//让thread1先执行
Thread.sleep(50);
thread2.start();
//主线程阻塞一会让所有子线程启动
Thread.sleep(100);
//中断线程2
thread2.interrupt();
}
}
输出如下,thread2结束了,并没有抛出InterruptedException异常
thread1:得到锁
0
thread2:结束
1
2
thread1:释放锁
4、tryLock(long time, TimeUnit unit)
可设置获取锁超时时间的重载方法则可被中断
public class TryLockTimeTest {
public static void main(String[] args) throws InterruptedException {
Lock lock = new ReentrantLock();
Thread thread1 = new Thread(() -> {
lock.tryLock();
System.out.println("thread1:得到锁");
//死循环
for (int i = 0; i < 3; i++) {
System.out.println(i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("thread1:释放锁");
lock.unlock();
});
Thread thread2 = new Thread(() -> {
boolean alreadyLock = false;
try {
//与tryLock的区别
alreadyLock = lock.tryLock(2, TimeUnit.SECONDS);
Thread.sleep(5000);
if (alreadyLock)
System.out.println("thread2:得到锁");
}
catch (Exception e){
e.printStackTrace();
}
finally {
if (alreadyLock){
lock.unlock();
}
}
System.out.println("thread2:结束");
});
thread1.start();
//让thread1先执行
Thread.sleep(50);
thread2.start();
//主线程阻塞一会让所有子线程启动
Thread.sleep(100);
//中断线程2
thread2.interrupt();
}
}
输出
thread1:得到锁
0
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireNanos(AbstractQueuedSynchronizer.java:936)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireNanos(AbstractQueuedSynchronizer.java:1247)
at java.util.concurrent.locks.ReentrantLock.tryLock(ReentrantLock.java:442)
at com.calulator.TryLockTimeTest.lambda$main$1(TryLockTimeTest.java:30)
at java.lang.Thread.run(Thread.java:748)
thread2:结束
1
2
thread1:释放锁
总结
上述的4个方法都是尝试获取锁的方法。
lock():得到锁继续往下执行,反之一直阻塞。不可被中断
lockInterruptibly():得到锁则继续往下,反之一直阻塞。可被中断
tryLock():得到锁继续往下执行并返回true,反之也是继续往下执行并返回false。不可被中断
tryLock(long time, TimeUnit unit):逻辑与tryLock(),只是增加超时机制,超时得不到锁就返回false。可被中断
重点:中断只有在一个线程在等待锁时生效,就如上述示例中的thread1和thread2,thread1是优先得到锁的,thread2在等待锁,只有thread2才能被interrupt中断。
且中断是有条件限制的,可见只在thread2中调用lock.lockInterruptibly()和tryLock(long time, TimeUnit unit)两个方法调用获取锁时才能被中断,该两个方法共性是接口声明时都抛出了InterruptedException异常