排它锁ReentrantLock,lock.lock()、lockInterruptibly()、tryLock()的区别

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异常

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值