现在的位置: 首页 > 综合 > 正文

Lock 和 Condition有什么作用

2020年02月19日 综合 ⁄ 共 1475字 ⁄ 字号 评论关闭

  Java 在语法层面已经有了 synchronized 来实现管程,为什么还要在 JDK 中提供了 Lock 和 Condition 工具类来做这样的事情,这属于重复造轮子吗?

  首先你可能会想到的是 synchronized 性能问题,但是我想告诉你的是 synchronized 在高版本的 JDK 中性能已经得到了大幅的提升,很多开发者开始提倡使用 synchronized,性能问题可以不断优化提升,它并不是重载轮子的原因。

  大家都知道管程帮助我们解决了多线程资源共享问题,但同时也带来了死锁的风险。

  产生死锁的四个必要条件:

  1. 互斥条件

  一个资源在同一时刻只能被一个线程操作。

  2. 占有且等待

  线程因为请求资源而阻塞时不会释放已经获取到的资源。

  3. 不可强行占有

  线程已经获取到的资源,在未释放前不允许被其他线程强行剥夺。

  4. 循环等待

  线程存在循环等待资源的关系(线程 T1 依次占有资源 A,B;线程 T2 依次占有资源 B,A;这就构成了循环等待资源关系)。

  当发生死锁的时候必然上面四个条件都会满足,那么只要我们破坏其中的任何一个条件,我们即可解决死锁问题。首先条件 1 无法破解,因为共享资源必须是互斥的,如果可以多个线程同时操作也没必要加锁了。

  使用 synchronized 来破解剩余的三个条件:

  1. 占有且等待

  synchronized 获取资源时候,只要资源获取不到,线程立即进入阻塞状态,并且不会释放已经获取的资源。那么我们可以调整一下获取共享资源的方式,我们通过一个锁中介,通过中介一次性获取线程需要的所有资源,如果存在单个资源不满足情况,直接阻塞,而不是获取部分资源,这样我们即可解决这个问题,破解该条件。

  2. 不可强行占有

  synchronized 获取不到资源时候,线程直接阻塞,无法被中断释放资源,因此这个条件 synchronized 无法破解。

  3. 循环等待

  循环等待是因为线程在竞争 2 个互斥资源时候会以不同的顺序去获取资源,如果我们将线程获取资源的顺序固定下来即可破解这个条件。

  综上我们可以知道 synchronized 不能破解“不可强行占有”条件,这就是 JDK 同时提供 Lock 这种管程的实现方式的原因。当然啦,Lock 使用起来也更加的灵活。例如我们有多个共享资源,锁是嵌套方式获取的,如线程需要先获取 A 锁,然后获取 B 锁,然后释放 A 锁,获取 C 锁,接着释放 B 锁,获取 D 锁 等等。这种嵌套获取锁的方式 synchronized 是无法实现的,但是 Lock 却可以帮助我们来解决这个问题。既然我们知道了 JDK 重造管程的原因。

  Lock提供的四种进入获取锁的方式:

  1. void lock();

  这种方式获取不到锁时候线程会进入阻塞状态,和 synchronized 类似。

  2. void lockInterruptibly() throws InterruptedException;

  这种方式获取不到锁线程同样会进入阻塞,但是它可以接收中断信号,退出阻塞。

  3. boolean tryLock();

  这种方式不管是否能获取到锁都不会阻塞而是立刻返回获取结果,成功返回 true,失败返回 false。

  4. boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

  这种方式获取不到锁的线程会进入阻塞状态,但是在指定的时间内如果仍未获得锁,则返回 false,否则返回 true。

  以上即为问题的答案,小伙伴们对这个答案是否满意呢?要了解更多技术知识请上学步园。

抱歉!评论已关闭.