如何实现ABC三个线程按顺序执行十次

Posted 张维鹏

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何实现ABC三个线程按顺序执行十次相关的知识,希望对你有一定的参考价值。

题目要求:创建三个线程,每个线程分别打印ABC,并按照ABC的顺序执行十次

题目可以使用多种不同的方式解决,下面我们分别使用 Condition 等待唤醒机制、Semaphore 信号量、CountDownLatch 闭锁、Thread.join() 方法四种方式实现题目要求。

一、使用一个 ReentrantLock 和 三个 Condition 来实现:

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

/**
 * 题目要求:ABC三个线程顺序执行10次
 * 实现思路:使用一个ReentrantLock 和 三个 Condition 来实现
 */
public class PrintABCUsingCondition
{
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition conditionA = lock.newCondition();
    private static Condition conditionB = lock.newCondition();
    private static Condition conditionC = lock.newCondition();

    public void execute(String flag)
    {
        lock.lock();

        for (int i = 1 ; i <= 10 ; i++){
            if ("A".equals(flag)) print(flag, conditionA, conditionB);
            if ("B".equals(flag)) print(flag, conditionB, conditionC);
            if ("C".equals(flag)) print(flag, conditionC, conditionA);
        }

        lock.unlock();
    }

    private void print(String name, Condition currentThread, Condition nextThread)
    {
        try{
            System.out.println(Thread.currentThread().getName()  + "-" + name);
            nextThread.signal();
            currentThread.await();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws InterruptedException
    {
        PrintABCUsingCondition myTask = new PrintABCUsingCondition();

        new Thread(() -> myTask.execute("A")).start();
        //必须确保线程A比另外两个线程先拿到ReentrantLock,所以让主线程sleep一段时间
        Thread.sleep(500);
        new Thread(() -> myTask.execute("B")).start();
        new Thread(() -> myTask.execute("C")).start();
    }
}

二、基于 Semaphore 信号量来实现:

import java.util.concurrent.Semaphore;

/**
 * 题目要求:ABC三个线程顺序执行10次
 * 实现思路:使用一个Semaphore信号量来实现
 */
class PrintABCUsingSemaphore
{
    private Semaphore semaphoreA = new Semaphore(1);
    private Semaphore semaphoreB = new Semaphore(0);
    private Semaphore semaphoreC = new Semaphore(0);

    private void printA(){
        print("A", semaphoreA, semaphoreB);
    }

    private void printB(){
        print("B", semaphoreB, semaphoreC);
    }

    private void printC(){
        print("C", semaphoreC, semaphoreA);
    }

    private void print(String name, Semaphore currentSemaphore, Semaphore nextSemaphore)
    {
        for (int i = 0; i < 10; i++){
            try {
                currentSemaphore.acquire();
                System.out.println(Thread.currentThread().getName() +" print "+ name);
                nextSemaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
    {
        PrintABCUsingSemaphore printABC = new PrintABCUsingSemaphore();
        new Thread(() -> printABC.printA()).start();
        new Thread(() -> printABC.printB()).start();
        new Thread(() -> printABC.printC()).start();
    }
}

三、基于 CountDownLatch 闭锁来实现:

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

/**
 *  题目要求:ABC三个线程顺序执行10次
 *  实现思路:使用 CountDownLatch 来实现:
 * (1)定义dependLatch(所依赖的latch名)、selfLatch(自己的latch名)
 * (2)首先调用所依赖的latch的await()方法,如果所依赖的latch的count为0,则重置所依赖的latch并打印需要输出的,最后将自身的count减去
 * (3)sum为需要执行的次数
 */
public class PrintABCUsingCountDownLatch implements Runnable {

    private static Map<String, CountDownLatch> countDownLatchMap = new HashMap<>();

    private String dependLatch;
    private String selfLatch;

    private PrintABCUsingCountDownLatch(String dependLatch, String selfLatch)
    {
        this.dependLatch = dependLatch;
        this.selfLatch = selfLatch;
    }

    @Override
    public void run()
    {
        for (int i = 0; i < 10; i++)
        {
            try {
                countDownLatchMap.get(dependLatch).await();
                countDownLatchMap.put(dependLatch, new CountDownLatch(1));

                System.out.println(Thread.currentThread().getName() + ":" + selfLatch);

                countDownLatchMap.get(selfLatch).countDown();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
    {
        String latchA = "A";
        String latchB = "B";
        String latchC = "C";

        countDownLatchMap.put(latchA, new CountDownLatch(1));
        countDownLatchMap.put(latchB, new CountDownLatch(1));
        countDownLatchMap.put(latchC, new CountDownLatch(1));

        //创建三个线程,但是此时由于三个CountDownLatch都不为0,所以三个线程都处于阻塞状态
        Thread threadA = new Thread(new PrintABCUsingCountDownLatch(latchC, latchA));
        Thread threadB = new Thread(new PrintABCUsingCountDownLatch(latchA, latchB));
        Thread threadC = new Thread(new PrintABCUsingCountDownLatch(latchB, latchC));
        threadA.start();
        threadB.start();
        threadC.start();
        //latchC 阻塞了 latchA;调用latchC的countDown()方法,先让latchC为0,使latchA先运行
        countDownLatchMap.get(latchC).countDown();
    }

四、 使用 Thread.join() 方法来实现:

/**
 * 题目要求:ABC三个线程顺序执行10次
 * 实现思路:使用 Thread.join() 方法来实现
 */
public class PrintABCUsingJoin
{
    public static void main(String[] args)
    {
        Thread t0 = new Thread(new Work((null)));
        Thread t1 = new Thread(new Work((t0)));
        Thread t2 = new Thread(new Work((t1)));
        t0.start();
        t1.start();
        t2.start();
    }
}

class Work implements Runnable
{
    private Thread beforeThread;
    public Work(Thread beforeThread)
    {
        this.beforeThread = beforeThread;
    }

    @Override
    public void run()
    {
        //调用前面线程的join方法
        if(beforeThread != null)
        {
            try{
                beforeThread.join();
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("当前线程:" + Thread.currentThread().getName());
    }
}

以上是关于如何实现ABC三个线程按顺序执行十次的主要内容,如果未能解决你的问题,请参考以下文章

多线程面试题之三线程按顺序交替打印ABC的方法

Vb.net 多个线程执行顺序的问题

多线程实现按顺序循环输出ABC

POSIX(Linux多线程)使用信号量三个线程顺序打印十次123

Jmeter--多个线程组顺序执行和并行执行

Java并发之线程