ReentrantLock的三种获取锁Lock,tryLock,lockInterruptibly的区别

重入锁有三种获取锁的方式,本文就是来说明三种方式的异同点的.

lock

public void lock()

获得锁。

  • 如果锁没有被另一个线程占用并且立即返回,则将锁定计数设置为1。
  • 如果当前线程已经保持锁定,则保持计数增加1,该方法立即返回。
  • 如果锁被另一个线程保持,则当前线程将被禁用以进行线程调度,并且在锁定已被获取之前处于休眠状态,此时锁定保持计数被设置为1。

tryLock

boolean tryLock();
  • 当获取锁时,只有当该锁资源没有被其他线程持有才可以获取到,并且返回true,同时设置持有count为1。
  • 当获取锁时,当前线程已持有该锁,那么锁可用时,返回true,同时设置持有count加1。
  • 当获取锁时,如果其他线程持有该锁,无可用锁资源,直接返回false,这时候线程不用阻塞等待,可以先去做其他事情。
  • 即使该锁是公平锁fairLock,使用tryLock()的方式获取锁也会是非公平的方式,只要获取锁时该锁可用那么就会直接获取并返回true。这种直接插入的特性在一些特定场景是很有用的。但是如果就是想使用公平的方式的话,可以试一试tryLock(0,TimeUnit.SECONDS),几乎跟公平锁没区别,只是会监测中断事件

使用标准模板:

Lock lock = ...;
if (lock.tryLock()) {
   try {
    // manipulate protected state
    } finally {
       lock.unlock();
    }
 } else {
   // perform alternative actions
 }

tryLock的重载方法:

boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
  • 获取锁成功或者超时之后返回。而且在公平锁和非公平锁的场景下都可以使用,只是会增加对中断事件的监测。
  • 当获取锁时,锁资源在超时时间之内变为可用,并且在等待时没有被中断,那么当前线程成功获取锁,返回true,同时当前线程持有锁的count设置为1.
  • 当获取锁时,在超时时间之内没有锁资源可用,那么当前线程获取失败,不再继续等待,返回false.
  • 当获取锁时,在超时等待时间之内,被中断了,那么抛出InterruptedException,不再继续等待.
  • 当获取锁时,在超时时间之内锁可用,并且当前线程之前已持有该锁,那么成功获取锁,同时持有count加1.

lockInterruptibly

void lockInterruptibly() throws InterruptedException;
  •     当获取锁时,锁资源可用,那么当前线程成功获得锁,同时持有count设置为1,返回true.
  •     当获取锁时,锁资源可用,当前线程已持有该锁,它成功获取该锁,同时持有count增加1,返回true.
  •     当获取锁时,锁资源不可用,那么该线程开始阻塞休眠等待,但是等待过程中如果有中断事件,那么会停止等待,立即返回.
  •     当获取锁时,锁资源不可用,线程开始阻塞休眠等待,如果等待过程中锁资源变为可用,那么当前线程成功获得锁,同时持有count设置为1,返回true.

lockInterruptibly()获取锁是以排他的模式获取,一旦被中断就放弃等待获取。在等待开始时首先检测中断状态,然后至少调用一次tryAcquire,成功获取就返回true。否则当前线程就开始排队,并且不断的被blocking、unblocking、invoking tryAcquire 直到获取成功或者被中断为止。



下面使用代码进行演示:

package com.springcloud.server.springserver.thread;

import java.util.concurrent.locks.ReentrantLock;

public class TestLockAndTryLock {
    private ReentrantLock rlock = new ReentrantLock();

    private void lockTest(){
        long currentTime = System.currentTimeMillis();
        try {
            rlock.lock();

            while (System.currentTimeMillis() - currentTime <= 1000){
                //assume do something
            }
            System.out.println("lockTest----current thread get the lock: " + Thread.currentThread().getName());
        }finally {
            rlock.unlock();
            System.out.println("lockTest----current thread release the lock:  " + Thread.currentThread().getName());
        }
    }

    private void tryLockTest(){
        long currentTime = System.currentTimeMillis();
        while (System.currentTimeMillis() - currentTime <= 100){
            //assume do something
        }
        if (rlock.tryLock()){
            try {
                System.out.println("tryLockTest----current thread get the lock: " + Thread.currentThread().getName());
            }finally {
                rlock.unlock();
                System.out.println("tryLockTest----current thread release the lock: " + Thread.currentThread().getName());
            }
        }else {
            System.out.println("tryLockTest----current thread CAN NOT get the lock: " + Thread.currentThread().getName());
        }
    }

    public static void main(String[] args){

        TestLockAndTryLock lockAndTryLock = new TestLockAndTryLock();

        Thread lockThread = new Thread(
                () -> lockAndTryLock.lockTest(), "Lock-Thread" );

        Thread tryLockThread = new Thread(
                () -> lockAndTryLock.tryLockTest(), "TryLock-Thread" );



        tryLockThread.start();
        lockThread.start();

    }

}

 输出结果:

lock()方法先获取锁,然后在执行任务的时候阻塞,tryLock()会在尝试加锁失败的时候返回false.

package com.springcloud.server.springserver.thread;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TestLockAndTryLock1 {
    private ReentrantLock rlock = new ReentrantLock();

    private void lockTest(){
        long currentTime = System.currentTimeMillis();
        try {
            rlock.lock();
            System.out.println("lockTest----current thread get the lock: " + Thread.currentThread().getName());
            while (System.currentTimeMillis() - currentTime <= 5000){
                //assume do something
            }
        }finally {
            rlock.unlock();
            System.out.println("lockTest----current thread release the lock:  " + Thread.currentThread().getName());
        }
    }

    private void tryLockInterruptTest(){
        long currentTime = System.currentTimeMillis();
        while (System.currentTimeMillis() - currentTime <= 100){
            //assume do something
        }
        try {
            System.out.println("Begin time: " + System.currentTimeMillis());
            if (rlock.tryLock(1, TimeUnit.SECONDS)){
                try {
                    System.out.println("tryLockInterruptTest----current thread get the lock: " + Thread.currentThread().getName());
                }finally {
                    rlock.unlock();
                    System.out.println("tryLockInterruptTest----current thread release the lock: " + Thread.currentThread().getName());
                }
            }else {
                System.out.println("End time: " + System.currentTimeMillis());
                System.out.println("tryLockInterruptTest----current thread CAN NOT get the lock: " + Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args){

        TestLockAndTryLock1 lockAndTryLock = new TestLockAndTryLock1();

        Thread lockThread = new Thread(
                () -> lockAndTryLock.lockTest(), "Lock-Thread" );

        Thread tryLockInterruptThread = new Thread(
                () -> lockAndTryLock.tryLockInterruptTest(), "TryLockInterrupt-Thread"
        );

        tryLockInterruptThread.start();
        lockThread.start();

    }

}

 输出结果:

lock()方法先获取锁,然后执行任务5秒,tryLock()方法先直接获取锁,获取不到就在1秒的时间内持续获取锁,超过时间还获取不到就返回false.

package com.springcloud.server.springserver.thread;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TestLockAndTryLock2 {
    private ReentrantLock rlock = new ReentrantLock();

    private void lockTest(){
        long currentTime = System.currentTimeMillis();
        try {
            rlock.lock();
            System.out.println("lockTest----current thread get the lock: " + Thread.currentThread().getName());
            while (System.currentTimeMillis() - currentTime <= 5000){
                //assume do something
            }
        }finally {
            rlock.unlock();
            System.out.println("lockTest----current thread release the lock:  " + Thread.currentThread().getName());
        }
    }
    private void tryLockInterruptTest(){
        long currentTime = System.currentTimeMillis();
        while (System.currentTimeMillis() - currentTime <= 100){
            //assume do something
        }
        try {
            System.out.println("Begin time: " + System.currentTimeMillis());
            if (rlock.tryLock(3, TimeUnit.SECONDS)){
                try {
                    System.out.println("tryLockInterruptTest----current thread get the lock: " + Thread.currentThread().getName());
                }finally {
                    rlock.unlock();
                    System.out.println("tryLockInterruptTest----current thread release the lock: " + Thread.currentThread().getName());
                }
            }else {
                System.out.println("End time: " + System.currentTimeMillis());
                System.out.println("tryLockInterruptTest----current thread CAN NOT get the lock: " + Thread.currentThread().getName());
            }
        } catch (InterruptedException e) {
            System.out.println("tryLockInterruptTest Interrupt----current thread is interrupted: " + Thread.currentThread().getName());
        }
    }

    public static void main(String[] args){
        TestLockAndTryLock2 lockAndTryLock = new TestLockAndTryLock2();
        Thread lockThread = new Thread(
                () -> lockAndTryLock.lockTest(), "Lock-Thread" );
        Thread tryLockInterruptThread = new Thread(
                () -> lockAndTryLock.tryLockInterruptTest(), "TryLockInterrupt-Thread"
        );
        tryLockInterruptThread.start();
        lockThread.start();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            System.out.println(Thread.currentThread().getName() + "is interrupted now. ");
        }
        tryLockInterruptThread.interrupt();
    }

}

lock()方法先获取锁,然后执行任务5秒,tryLock()方法先直接获取锁,获取不到就在1秒的时间内持续获取锁,在获取锁的过程中,主线程(main)以通知的方式中断tryLockInterruptThread线程,tryLock()方法可以响应中断.


package com.springcloud.server.springserver.thread;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class TestLockInterruptibly {

    final Lock lock = new ReentrantLock();

    public static void main(String[] args) throws Exception {
        TestLockInterruptibly testLockInterruptibly = new TestLockInterruptibly();
        Thread lockThread = new Thread(
                () -> testLockInterruptibly.lock()
        );
        Thread interruptiblyThread = new Thread(
                () -> testLockInterruptibly.lockInterruptibly()
        );
        lockThread.start();
        interruptiblyThread.start();

        TimeUnit.SECONDS.sleep(2);
//        interruptiblyThread.interrupt();
    }

    public void lockInterruptibly()  {
        long currentTime = System.currentTimeMillis();
        while (System.currentTimeMillis() - currentTime <= 500){
            //assume do something
        }
        try {
            lock.lockInterruptibly();
            System.out.println("lockInterruptibly获取Lock锁");
        } catch (InterruptedException e) {
            System.out.println("lockInterruptibly捕捉InterruptedException异常");
        }finally {
            lock.unlock();
            System.out.println("lockInterruptibly释放Lock锁");
        }
    }

    public void lock()  {
        long currentTime = System.currentTimeMillis();
        try {
            lock.lock();
            System.out.println("lock获取Lock锁");
            while (System.currentTimeMillis() - currentTime <= 5000){
                //assume do something
            }
        }finally {
            lock.unlock();
            System.out.println("lock释放Lock锁");
        }
    }

}

一般情况下,lockInterruptibly()会阻塞直到获取lock锁,此时和普通的lock()作用差不多,输出结果:

 

当我们打开main方法里面的注释,结果就不一样了,输出结果:

lockInterruptibly()在阻塞的过程中可以响应中断,并可以结束线程.此处抛异常原因是并没有获取锁,却去解锁(unLock()),普通的lock()方法无法响应中断.

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值