java多线程---重入锁ReentrantLock

Posted Ch1nYK

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java多线程---重入锁ReentrantLock相关的知识,希望对你有一定的参考价值。

1.定义
重入锁ReentrantLock,支持重入的锁,表示一个线程对资源的重复加锁。
2.底层实现
每个锁关联一个线程持有者和计数器,当计数器为0时表示该锁没有被任何线程持有,那么任何线程都可能获得该锁而调用相应的方法;成功后,JVM会记下锁的持有线程,并且将计数器置为1;此时其它线程请求该锁,则必须等待;而该持有锁的线程如果再次请求这个锁,就可以再次拿到这个锁,同时计数器会递增;当线程退出同步代码块时,计数器会递减,如果计数器为0,则释放该锁。
3.使用样例

eg:

import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTest implements Runnable{
    public static int i = 100;
    public static ReentrantLock rl = new ReentrantLock();
    
    @Override
    public void run() {
        while(true){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            rl.lock();
            if(i>0){
                System.out.println(Thread.currentThread().getName() + " : " + i--);
            }
            rl.unlock();
        }
    }
    
    public static void main(String[] args) {
        ReentrantLockTest rlt = new ReentrantLockTest();
        Thread t1 = new Thread(rlt);
        Thread t2 = new Thread(rlt);
        t1.start();
        t2.start();
    }

}

中断响应
synchronized:线程等待锁,要么获得锁继续执行,要么保持等待。
ReentrantLock:等待锁的过程中,可以根据需求取消对锁的请求。
eg:

import java.util.concurrent.locks.ReentrantLock;

public class IntLock implements Runnable {
    int lock;
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();
    
    public IntLock(int lock){
        this.lock = lock;
    }
    
    
    @Override
    public void run() {
        try{
            if(lock == 1){
                try{
                    lock1.lockInterruptibly();      // 如果当前线程未被中断,则获取锁。
                }catch(Exception e){
                    e.printStackTrace();
                }
                lock2.lockInterruptibly();
                System.out.println(Thread.currentThread().getId()+"执行完毕");
            }else{
                lock2.lockInterruptibly();
                try{
                    Thread.sleep(1000);
                }catch(Exception e){
                    
                }
                lock1.lockInterruptibly();
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(lock1.isHeldByCurrentThread()){      //查询当前线程是否保持此锁
                lock1.unlock();
            }
            if(lock2.isHeldByCurrentThread()){      //查询当前线程是否保持此锁
                lock2.unlock();
            }
            System.out.println(Thread.currentThread().getId()+":线程退出");
        }

    }
    
    public static void main(String[] args) throws InterruptedException {
        IntLock l1 = new IntLock(1);
        IntLock l2 = new IntLock(2);
        Thread t1 = new Thread(l1);
        Thread t2 = new Thread(l2);
        t1.start();
        t2.start();
        Thread.sleep(2000);
        t2.interrupt();         //中断线程,不中断,则产生死锁
        
    }

}

锁申请等待限时
如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。

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

public class TimeLock implements Runnable {

    public static ReentrantLock rl = new ReentrantLock();
    
    @Override
    public void run() {
        try {
            if(rl.tryLock(5, TimeUnit.SECONDS)){
                Thread.sleep(6000);
                System.out.println(Thread.currentThread().getId()+"执行完毕");
            }else{
                System.out.println(Thread.currentThread().getId()+"get lock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            if(rl.isHeldByCurrentThread())rl.unlock();
        }
    }
    
    public static void main(String[] args) {
        TimeLock tl = new TimeLock();
        Thread t1 = new Thread(tl);
        Thread t2 = new Thread(tl);
        t1.start();
        t2.start();
    }

}

公平锁

在ReentrantLock中很明显可以看到其中同步包括两种,分别是公平的FairSync和非公平的NonfairSync。公平锁的作用就是严格按照线程启动的顺序来执行的,不允许其他线程插队执行的;而非公平锁是允许插队的。默认情况下ReentrantLock是通过非公平锁来进行同步的,包括synchronized关键字都是如此,因为这样性能会更好。

public ReentrantLock(boolean fair) //如果此锁应该使用公平的排序策略,则该参数为 true

import java.util.concurrent.locks.ReentrantLock;

public class FairLock implements Runnable{

    public static ReentrantLock rl = new ReentrantLock(true);
    
    @Override
    public void run() {
        while(true){
            try {
                rl.lock();
                System.out.println(Thread.currentThread().getName()+" : get lock");
            } catch (Exception e) {
            }finally{
                rl.unlock();
            }
        }
    }
    
    public static void main(String[] args) {
        FairLock fl = new FairLock();
        Thread t1 = new Thread(fl,"Thread_One");
        Thread t2 = new Thread(fl,"Thread_Two");
        t1.start();
        t2.start();
    }

}

在重入锁的实现中,包含3个要素

1.原子状态,使用CAS操作来存储当前锁的状态,判断锁是否被别的线程持有
2.等待队列,所有没有请求到锁的线程,会进入到队列进行等待,待有线程释放锁后,系统能从等待队列唤醒一个线程继续工作。
3.阻塞原语park()和unpark(),用来挂起和恢复线程,没有得到锁的线程会被挂起







以上是关于java多线程---重入锁ReentrantLock的主要内容,如果未能解决你的问题,请参考以下文章

并发编程-concurrent指南-Lock-可重入锁(ReentrantLock)

Java多线程_ReentrantLock

Java 多线程 重入锁

java 多线程-可重入锁

6.23Java多线程可重入锁实现原理

JAVA多线程重入锁ReentrantLock应用