当前位置: 首页 > article >正文

顺序打印数字的进一步理解

之前博客写了篇博文,面试时要求使用多线程顺序打印ABC循环20次,这是我当时使用join函数实现代码:

public class TestABCJoin {
    public static void main(String[] args) {
        // 创建任务
        Runnable taskA = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
        };
        Runnable taskB = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
        };
        Runnable taskC = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i);
            }
        };

        // 循环 20 次
        for (int i = 0; i < 20; i++) {
            Thread threadA = new Thread(taskA, "A");
            Thread threadB = new Thread(taskB, "B");
            Thread threadC = new Thread(taskC, "C");

            try {
                threadA.start(); // 启动 A
                threadA.join();  // 等待 A 执行完毕
                threadB.start(); // 启动 B
                threadB.join();  // 等待 B 执行完毕
                threadC.start(); // 启动 C
                threadC.join();  // 等待 C 执行完毕
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
}

这两天复习多线程,想到condition也可以实现这个需求,先贴上代码:

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

public class TestABCLockCondition {
    public static void main(String[] args) {
        Alternate alternate = new Alternate();
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                alternate.loopA(i);
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                alternate.loopB(i);
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                alternate.loopC(i);
            }
        }, "C").start();
    }
}

class Alternate {
    private int number = 1; // 当前应执行的线程标记:1-A, 2-B, 3-C
    private final Lock lock = new ReentrantLock();
    private final Condition conditionA = lock.newCondition();
    private final Condition conditionB = lock.newCondition();
    private final Condition conditionC = lock.newCondition();

    public void loopA(int totalLoop) {
        lock.lock();
        try {
            while (number != 1) {
                conditionA.await();
            }
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
            }
            number = 2;
            conditionB.signal();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }

    public void loopB(int totalLoop) {
        lock.lock();
        try {
            while (number != 2) {
                conditionB.await();
            }
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
            }
            number = 3;
            conditionC.signal();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }

    public void loopC(int totalLoop) {
        lock.lock();
        try {
            while (number != 3) {
                conditionC.await();
            }
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + "\t" + i + "\t" + totalLoop);
            }
            number = 1;
            conditionA.signal();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
}

思考了下这两种方案的优缺点(deepseek总结):
使用 join() 实现顺序打印是一种简单直观的方式,适合小规模任务。但对于高并发场景,建议使用更高效的同步机制(如 ReentrantLock 和 Condition)。

好奇具体是为什么:
可以发现,第一种方法每次循环都需要创建新的线程(new Thread()),并在任务完成后销毁线程。我们知道线程的创建和销毁是非常昂贵的操作,尤其是在高并发场景下,频繁创建线程会导致性能急剧下降。
同时join() 会阻塞当前线程(通常是主线程),直到目标线程执行完毕。

使用信号量在高并发场景下的优势:
Condition 提供了 await() 和 signal() 方法,可以精确控制线程的等待和唤醒。
ReentrantLock 和 Condition 可以实现非阻塞的线程协作,避免主线程被阻塞。


http://www.kler.cn/a/531663.html

相关文章:

  • RDP协议详解
  • 【MySQL】语言连接
  • 纯后训练做出benchmark超过DeepseekV3的模型?
  • Linux02——Linux的基本命令
  • 电子电气架构 --- 汽车电子拓扑架构的演进过程
  • 「全网最细 + 实战源码案例」设计模式——桥接模式
  • M. Triangle Construction
  • 注解与反射基础
  • 巧妙利用数据结构优化部门查询
  • Nginx 命令行参数
  • 深入探讨DICOM医学影像中的WADO服务及其具体实现
  • 内核定时器1-普通定时器
  • 浅谈线段树
  • 【Linux】25.进程信号(2)
  • 语言月赛 202412【正在联系教练退赛】题解(AC)
  • 电动汽车常见概念
  • e2studio开发RA2E1(5)----GPIO输入检测
  • Deepseek 数据蒸馏、芯片禁售引发中美AI 之战
  • 嵌入式学习---蜂鸣器篇
  • LeetCode:53.最大子序和
  • 数据 类型
  • 【LeetCode 刷题】回溯算法(3)-子集问题
  • 基于脉冲响应不变法的IIR滤波器设计与MATLAB实现
  • 10.8 LangChain Output Parsers终极指南:从JSON解析到流式处理的规范化输出实践
  • 【R语言】环境空间
  • 【最后203篇系列】006 -使用ollama运行deepseek-r1前后端搭建