【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. 参考文献

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值