关于Java 重入锁的理解

通过查看 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

下回分解


公众号:BinrenCode

猜你喜欢

转载自blog.csdn.net/jiangbr/article/details/79337547
今日推荐