【多线程】多线程打印1~100

前言:上一篇文章我们使用了 ReentrantLock+Condition 实现了多线程打印 ABC,这篇文章我们来实现多线程打印数字 1~100。

(一)题目

(1)题目 1:双线程打印

使用两个线程交替打印数字。

线程 A 打印奇数(1,3,5...),线程 B 打印偶数(2,4,6...),交替输出1~100。

(2)题目 2:多线程打印

使用 N 个线程顺序循环打印从 0 至 100。

(二)解法

(1)题目 1:双线程打印

这种解法实现起来比较简单,每个线程执行的次数是固定的。

java 复制代码
public class PrintNum {
    private static int state = 0;
    private static int times = 50;
    private static Lock lock = new ReentrantLock();
    private static Condition c1 = lock.newCondition();
    private static Condition c2 = lock.newCondition();

    private static void printN(int flag, Condition current, Condition next) {
        lock.lock();
        try {
            for (int i = 0; i < times; i++)
            {
                while(state % 2 != flag) current.await();

                System.out.println(Thread.currentThread().getName() + ": " + (2 * i + flag + 1));
                state ++;
                next.signal();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        new Thread(() -> {
            printN(0, c1, c2);
        }, "Thread-1").start();

        new Thread(() -> {
            printN(1, c2, c1);
        }, "Thread-2").start();
    }
}
(2)题目 2:多线程打印

与上一题不同的是,这里每个线程的执行次数不是固定的,对于每个线程需要判断 state 是否已经达到 100 了,达到就不能继续执行了。

但是因为多线程并发执行,state 的值一直在变化,所以如何保证不超输出,是一个需要注意的问题。

  1. while 判断的时候,需要加上一个条件 state < 100。也就是说,如果已经达到 100 了,就不必再进入阻塞队列等待唤醒。
  2. while 执行完毕之后,按理来说就可以执行输出了,但是还需要加上一个判断,只有当 state<100 时才执行。这是为了防止当前线程在阻塞队列的时候有别的线程将 state 加够了。
  3. 当到达 100 之后,需要唤醒所有的线程。防止有的线程在等待队列中始终无法被唤醒。
java 复制代码
public class PrintNum2 {
    private static int state = 0;
    private static int threadCnt = 7;
    private static Lock lock = new ReentrantLock();
    private static Condition[] conditions = new Condition[threadCnt];

    static {
        for (int i = 0; i < threadCnt; i++) {
            conditions[i] = lock.newCondition();
        }
    }

    private static void printN(int flag, Condition current, Condition next) {
        lock.lock();

        try {
            while(state < 100)
            {
                while(state < 100 && state % threadCnt != flag) current.await(); //双重检测

                if(state < 100) { //双重检测
                    System.out.println(Thread.currentThread().getName() + ": " + (state + 1));
                    state ++;
                    next.signal();
                }
                else{
                    for(Condition c : conditions) c.signal(); //到达100了,唤醒所有线程,防止有线程在等待队列中无法被唤醒
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        for(int i = 0; i < threadCnt; i ++)
        {
            int tmpI = i;
            new Thread(() -> {
                printN(tmpI, conditions[tmpI], conditions[(tmpI + 1) % threadCnt]);
            }, "Thread-" + (i + 1)).start();
        }
    }
}
相关推荐
·薯条大王9 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
ZJH__GO12 小时前
网络编程v4pro--实现聊天室文件传输功能
java·服务器·网络·计算机网络
程序员黑豆12 小时前
Windows 系统 Java 环境变量配置全攻略:解决“不是内部或外部命令”
java·前端·ai编程
命运之光12 小时前
【C语言完整代码】就诊信息管理系统
java·c语言·开发语言
凤山老林12 小时前
Spring Boot @Async 线上实战:从默认配置到生产级线程池治理
java·spring boot·后端
marvelyu13 小时前
每天10分钟学会OceanBase系列(Day 20):跨机房容灾实战——构建多数据中心高可用架构
java·大数据·数据库
AI人工智能+电脑小能手14 小时前
大白话说Java设计模式-04-工厂方法模式(业务实战篇)
java·设计模式·工厂方法模式·架构设计·代码解耦
BUG指挥官14 小时前
Sa-Token和Spring Security对比
java·后端·spring
小当家.10514 小时前
深入理解 ReAct Agent:从原理到 Java 实战
java·react.js·agent·react·架构设计·agent设计
geminigoth14 小时前
Spring AI Alibaba 入门开发一(备份)
java·人工智能·spring