JAVA并发多个线程交替打印

Posted Kant101

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA并发多个线程交替打印相关的知识,希望对你有一定的参考价值。

1. 概述

多个线程交替打印是面试中最长考察JAVA并发相关的题目了,其目的在于考察对Java的J.U.C是否能熟练的使用。

例如:
1、3个线程交替打印A、B、C;
2、3个线程轮翻打印自然数;


2. 3个线程交替打印A、B、C

2.1 代码

package cn.pku.edu.algorithm.concurrent;

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

/**
 * @author allen
 * @date 2022/9/13
 */
public class PrintCharAlternately 

    public static void main(String[] args) throws InterruptedException 
        ReentrantLock lock = new ReentrantLock();
        Condition conditionA = lock.newCondition();
        Condition conditionB = lock.newCondition();
        Condition conditionC = lock.newCondition();

        Thread threadA = new Thread(new SyncPrinter(lock, conditionA, conditionB, 'A'), "threadA");
        Thread threadB = new Thread(new SyncPrinter(lock, conditionB, conditionC, 'B'), "threadB");
        Thread threadC = new Thread(new SyncPrinter(lock, conditionC, conditionA, 'C'), "threadC");

        threadA.start();
        Thread.sleep(1000);
        threadB.start();
        Thread.sleep(1000);
        threadC.start();
        Thread.sleep(1000);
    


class SyncPrinter implements Runnable 

    // 打印次数
    private static final int PRINT_COUNT = 10;

    private final ReentrantLock reentrantLock;

    private final Condition thisCondition;

    private final Condition nextCondition;

    private final char printChar;

    public SyncPrinter(ReentrantLock reentrantLock, Condition thisCondition, Condition nextCondition, char printChar) 
        this.reentrantLock = reentrantLock;
        this.thisCondition = thisCondition;
        this.nextCondition = nextCondition;
        this.printChar = printChar;
    

    @Override
    public void run() 
        // 获取打印锁,进入临界区
        reentrantLock.lock();
        try 
            // 连续打印 PRINT_COUNT 次
            for (int i = 0; i < PRINT_COUNT; i++) 
                // 打印字符
                System.out.println(Thread.currentThread().getName() + " print: " + printChar + " " + (i + 1) + " times");
                // 使用nextCondition唤醒下一个线程
                // 因为只有一个线程在等待,所以signal和signalAll都可以
                nextCondition.signalAll();
                // 不是最后一次则通过thisCondition等待被唤醒
                // 必须要加判断,不然虽然能够打印10次,但是10次后就会被直接锁死
                if (i < PRINT_COUNT - 1) 
                    try 
                        Thread.sleep(1000);
                        thisCondition.await();
                     catch (Exception e) 
                        e.printStackTrace();
                    
                
            
         finally 
            reentrantLock.unlock();
        
    


2.2 测试


3. 3个线程轮翻打印自然数

3.1 代码

package cn.pku.edu.algorithm.concurrent;

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

/**
 * @author allen
 * @date 2022/9/13
 */
public class PrintNumberAlternately 
    public static void main(String[] args) 
        ReentrantLock lock = new ReentrantLock();
        Condition conditionA = lock.newCondition();
        Condition conditionB = lock.newCondition();
        Condition conditionC = lock.newCondition();

        Thread thread1 = new Thread(new SyncNumberPrinter(lock, conditionA, conditionB), "thread1");
        Thread thread2 = new Thread(new SyncNumberPrinter(lock, conditionB, conditionC), "thread2");
        Thread thread3 = new Thread(new SyncNumberPrinter(lock, conditionC, conditionA), "thread3");

        thread1.start();
        thread2.start();
        thread3.start();
    


class SyncNumberPrinter implements Runnable 

    // 所有线程公用的数字
    private static volatile int num = 0;

    // 每个线程打印的次数
    private final int PRINT_TIMES = 1000;

    private final ReentrantLock reentrantLock;

    private final Condition currentCondition;

    private final Condition nextCondition;

    public SyncNumberPrinter(ReentrantLock reentrantLock, Condition currentCondition, Condition nextCondition) 
        this.reentrantLock = reentrantLock;
        this.currentCondition = currentCondition;
        this.nextCondition = nextCondition;
    

    @Override
    public void run() 
        try 
            // 获取打印锁
            reentrantLock.lock();
            for (int i = 0; i < PRINT_TIMES; i++) 
                System.out.println(Thread.currentThread().getName() + " print: " + num);
                num++;
                Thread.sleep(1000);
                // 打印完一次后,唤醒在下一个条件下等待的线程
                nextCondition.signalAll();
                if (i < PRINT_TIMES - 1) 
                    // 打印完,当前线程释放锁,并等待在当前条件下,等待被别的线程唤醒
                    currentCondition.await();
                
            
         catch (Exception e) 
            e.printStackTrace();
         finally 
            // 释放打印锁
            reentrantLock.unlock();
        
    

3.2 测试


4. 参考文献

以上是关于JAVA并发多个线程交替打印的主要内容,如果未能解决你的问题,请参考以下文章

[Java并发编程实战] 基础知识

[Java并发编程实战] 基础知识

Java并发编程入门

Java面试之多线程

Java面试之多线程

交替打印ABC多线程(互斥量+条件变量)