开启成长之旅!这是我参与「日新计划 12 月更文应战」的第28天,点击查看活动概况

一. 前言

近日壹哥的一个学生在参加某公司校招面试时,遇到一个多个线程次序履行的面试题,特意记录下来和咱们共享一下,这个标题的具体要求是这样的:

假设有3个线程 a,b,c,要求三个线程一同进入到安排妥当态,履行时必定 依照 a–>b–>c的次序履行 。即使 a或许b线程进入 到了 堵塞态,也必定 依照a–>b–>c的次序运行线程 。请问该如何保证完成这个需求呢?

二. 解决计划

关于这道题,壹哥百度一下网上常见的完成思路,大致有4种解决计划:

  1. 经过join()办法使当前线程“堵塞”,等候指定线程履行完毕后持续履行;
  2. 经过倒数计时器CountDownLatch完成;
  3. 经过创立单一化线程池 newSingleThreadExecutor()完成;
  4. 经过ReentrantLock 中的条件变量完成;

今天壹哥先运用ReentrantLock 的条件变量来完成这个标题中的需求。

三. 运用ReentrantLock 条件变量

首先咱们来了解一下,什么是ReentrantLock 条件变量(Condition)。

ReentrantLock 中的条件变量功能,类似于一般 synchronized 的 wait、notify,咱们能够运用Reentrantlock 锁,配合 Condition 目标上的 await()和 signal()或 signalAll()办法,来完成线程间协作。与synchronized的wait和notify不同之处在于,ReentrantLock中的条件变量能够有多个,能够完成更精密的操控线程。

Condition中常用的办法API有如下这些:

使用ReentrantLock中的条件变量,让多个线程顺序执行
使用ReentrantLock中的条件变量,让多个线程顺序执行​编辑

ReentrantLock代码完成:

class ShareDataLock{
    // 线程履行的条件 1:线程1履行 2:线程2履行 3:线程3履行
    int number =1;
    // 锁
    Lock lock = new ReentrantLock();
    // 从锁中获得3个条件变量
    Condition condition1 = lock.newCondition();
    Condition condition2 = lock.newCondition();
    Condition condition3 = lock.newCondition();
    // 第一个线程run之后履行的办法
    public void f1(){
        lock.lock();
        try {
            // 假如条件值不为1 就挂起等候
            while(number!=1){
                condition1.await();
            }
            // 成心堵塞100毫秒,看看其他的线程会不会不再排队
            Thread.sleep(100);
            System.out.println("------1--------");
            // 线程1 履行完毕 把变量设置为2
            number = 2;
            // 唤醒第2个条件变量
            condition2.signal();
        } catch (Exception e) {
          e.printStackTrace();
        } finally {
            // 不管抛没抛出反常都要解锁,避免线程死锁
          lock.unlock();
        }
    }
    public void f2(){
        lock.lock();
        try {
            while(number!=2){
                condition2.await();
            }
            System.out.println("------2--------");
            number = 3;
            condition3.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void f3(){
        lock.lock();
        try {
            while(number!=3){
                condition3.await();
            }
            System.out.println("------3--------");
            number = 1;
            condition1.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
public class SynchronizedAndReentrantLockDemo {
    public static void main(String[] args) {
        ShareDataLock shareDataLock = new ShareDataLock();
        for (int i = 0; i < 10; i++) {
            // 3个线程别离履行1,2,3 3个办法 ,而且一起安排妥当
            new Thread(()->shareDataLock.f1(),"AA").start();
            new Thread(()->shareDataLock.f2(),"bb").start();
            new Thread(()->shareDataLock.f3(),"cc").start();
        }
    }
}

使用ReentrantLock中的条件变量,让多个线程顺序执行

代码履行作用如下图:

使用ReentrantLock中的条件变量,让多个线程顺序执行
使用ReentrantLock中的条件变量,让多个线程顺序执行

现在咱们就会发现,3个线程现已能够被随意操控了,你会了吗?

四. 后话

如上文所述,让多个线程按次序履行,网上常见的解决计划有4种。但咱们要注意的是,面试官出这个题有一个先决条件,“要让所有的线程一起安排妥当 ,所以咱们就能够扫除运用join办法和运用单一化线程池的计划了。那么要想完成这个面试题中的需求,比较靠谱的办法只剩下ReentrantLock 中的条件变量和运用倒数计时器CountDownLatch两种计划了 。今天咱们暂时先介绍条件变量的办法,壹哥会在日后的文章中介绍怎样运用CountDownLatch 让多个线程有序履行, 敬请各位粉丝儿们持续等待哦。