ReentrantLock

ReentrantLock

学习ReentrantLock之前建议去看,Java锁这些基础知识和synchronized的原理。当然有操作系统的基础就更好了。


ReentantLock 实现接口 Lock ,并实现了接口中定义的方法,他是一种可重入锁,除了能完成 synchronized 所能完成的所有工作外,还提供了: 可响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法。ReentrantLock故名思意就是可重入锁。

Lock接口实现方法

  • void lock(): 执行此方法时, 如果锁处于空闲状态, 当前线程将获取到锁.
  • boolean tryLock():如果锁可用, 则获取锁, 并立即返回 true, 否则返回 false.
  • tryLock(long timeout TimeUnit unit):如果锁在给定等待时间内没有被另一个线程保持,则获取该锁。
  • void unlock():执行此方法时, 当前线程将释放持有的锁.
  • Condition newCondition():条件对象,获取等待通知组件。
  • getHoldCount() :查询当前线程保持此锁的次数,也就是执行此线程执行 lock 方法的次数。
  • getQueueLength():返回正等待获取此锁的线程估计数,比如启动 10 个线程,1 个线程获得锁,此时返回的是 9
  • getWaitQueueLength:(Condition condition)返回等待与此锁相关的给定条件的线程估计数。
  • hasQueuedThread(Thread thread):查询给定线程是否等待获取此锁
  • isFair():该锁是否公平锁
  • isHeldByCurrentThread(): 当前线程是否保持锁锁定,线程的执行 lock 方法的前后分别是 false 和 true
  • isLock():此锁是否有任意线程占用
  • lockInterruptibly():如果当前线程未被中断,获取锁

ReentrantLock构造方法

ReentrantLock默认是非公平锁的。ReentrantLock是可重入锁,也可以根据构造方法,设置为公平的或非公平的。公平锁:先来后到,非公平锁:允许尝试插队,插队不不成功就排队。

public ReentrantLock() {
    sync = new NonfairSync();
}
 
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

ReentrantLock 与 synchronized

  • ReentrantLock 通过方法 lock()与 unlock()来进行加锁与解锁操作,与 synchronized 会 被 JVM 自动解锁机制不同,ReentrantLock 加锁后需要手动进行解锁。
  • ReentrantLock 相比 synchronized 的优势是可中断、公平锁、多个锁。
  • synchronized是Java关键字,ReentrantLock的Java类
  • ReentrantLock的自由度比synchronized高,可中断,可公平锁、多个锁

Condition类

Condition用来代替Object 类wait 方法和notify 方法等,两者可以等价。

  • Condition 类的 awiat 方法和 Object 类的 wait 方法等效
  • Condition 类的 signal 方法和 Object 类的 notify 方法等效
  • Condition 类的 signalAll 方法和 Object 类的 notifyAll 方法等效
  • ReentrantLock 类可以唤醒指定条件的线程,而 object 的唤醒是随机的

Condition类和synchronized传统的唤醒方式对比:

public class testLock {
    private int num = 0;
    Lock lock = new ReentrantLock();
    Condition cdt = lock.newCondition();
    public synchronized void increment() throws InterruptedException {
        while (num != 0 )  //如果有东西就等待
            this.wait();
        //增加
        num++;
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        //操作完毕通知其他线程
        this.notify();
    }
    public synchronized void decrement() throws InterruptedException {
        while (num == 0 )  //没东西等待
            this.wait();
        //减小
        num--;
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        //操作完毕通知其他线程
        this.notify();
    }

    public void increment2() throws InterruptedException {
        lock.lock();
        while (num != 0 )  //如果有东西就等待
            cdt.await();
        //增加
        num++;
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        //操作完毕通知其他线程
        cdt.signal();
        lock.unlock();
    }
    public void decrement2() throws InterruptedException {
        lock.lock();
        while (num == 0 )  //没东西等待
            cdt.await();
        //减小
        num--;
        System.out.println(Thread.currentThread().getName()+"=>"+num);
        //操作完毕通知其他线程
        cdt.signal();
        lock.unlock();
    }

    public static void main(String[] args) {
        testLock test = new testLock();
        /*
        new Thread(()->{
            try {
                for(int i = 0;i<10;i++)
                    test.increment();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"A").start();
        new Thread(()->{
            try {
                for(int i = 0;i<10;i++)
                    test.decrement();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"B").start();
        */

        new Thread(()->{
            try {
                for(int i = 0;i<10;i++)
                    test.increment2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"C").start();
        new Thread(()->{
            try {
                for(int i = 0;i<10;i++)
                    test.decrement2();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"D").start();
    }
}

还有些基础知识:awiat 方法会释放线程持有的锁,至于为什么await()后面还要加unlock(),那是因为当线程被其他线程唤醒时,会获得锁,所以用完后还是需要unlock()。

无非就下面两种情况:

  • lock()获得锁—>unlock()释放锁
  • lock()获得锁—>awiat()等待并释放锁—>被其他线程signal()唤醒获得锁—>unlock()释放锁

至于调不调用awiat()完全看当前拿到锁的线程十分有条件完成下一步操作。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值