多线程轮流打印 ABC

写作初衷:网上多线程轮流打印 ABC 的例子已经很多了,但不是自己的逻辑沉淀不出知识。
最近考虑通过实现 多线程轮流打印 ABC, 多线程累加求和,简单总结下并发相关的知识点

内容说明:

  1. 仅实现了 volatile + synchronized + wait-notify 机制,目的是尽可能从简单的逻辑过渡
  2. 初步尝试了代码优化,即减少代码冗余,进行代码重构

1. 重构前:多个 Runnable 实现类

package com.youga.concurrent;

class ThreadPrintA implements Runnable{

    String s;
    ThreadPrintA(String s){
        this.s = s;
    }
    @Override
    public void run() {
        Object o = new Object();
        synchronized (o){
            if(!s.equals("A")){
                try {
                    o.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.print(s + " ");
            o.notify();
        }
    }
}
class ThreadPrintB implements Runnable{

    String s;
    ThreadPrintB(String s){
        this.s = s;
    }
    @Override
    public void run() {
        Object o = new Object();
        synchronized (o){
            if(!s.equals("B")){
                try {
                    o.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.print(s + " ");
            o.notify();
        }
    }
}
class ThreadPrintC implements Runnable{

    String s;
    ThreadPrintC(String s){
        this.s = s;
    }
    @Override
    public void run() {
        Object o = new Object();
        synchronized (o){
            if(!s.equals("C")){
                try {
                    o.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println(s);
            o.notify();
        }
    }
}

/**
 * 需求分析:现在仅实现了竞争打印,需要保证次序打印
 * ① 按 A,B,C 次序打印
 * ② 循环打印
 */
public class PrintAbc {
    public static void main(String[] args) throws InterruptedException {
        while(true){
            new Thread(new ThreadPrintA("A")).start();
            Thread.sleep(10);
            new Thread(new ThreadPrintB("B")).start();
            Thread.sleep(10);
            new Thread(new ThreadPrintC("C")).start();
            Thread.sleep(10);
        }
    }
}

tips :若 main() 函数中启动每个线程时未加延迟,则不能保证 A B C 线程是按照启动顺序执行的

基本逻辑:在每个 Runnable 实现类中判断传入参数是否为待打印字符,不是则阻塞至对应的线程打印完毕

重构逻辑:利用 ABC 三者的关系,修改字符串判断的逻辑:通过类变量动态获取当前需要打印的字符串

2. 重构后:一个 Runnable 实现类

class ThreadPrint implements Runnable{
    private static volatile int cnt = 0;
    private String s;
    ThreadPrint(String s){
        this.s = s;
    }
    @Override
    public void run() {
        Object o = new Object();
        synchronized (o){
            String ss = String.valueOf((char)('A' + cnt));
            if(!s.equals(ss)){
                try {
                    o.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.print(s);
            o.notify();
            if(cnt == 2) System.out.println();
            cnt = (cnt + 1) % 3;
        }
    }
}

/**
 * ① 按 A,B,C 次序打印
 * ② 循环打印
 * ③ 代码重构
 */
public class PrintAbc1 {
    public static void main(String[] args) throws InterruptedException {
        while(true){
            for(int i = 0; i < 3; i++){
                new Thread(new ThreadPrint(String.valueOf((char)('A' + i)))).start();
                Thread.sleep(100);
            }
        }
    }
}

为啥用 volatile 和 static 修饰 cnt,这就不说了,说出来的都是别人总结出来的,自己实践下最好

实践之后也不是自己的,因为还涉及到 语言特性,编译原理,CPU,指令架构…

摸清楚这些后,还不是你的,做人要诚实,但也要有所追求,认识这点的意义在于:或许有一天有些东西是属于你的

我老是觉得:从这个层面来想,学习 Java 是可以 上穷碧落下黄泉的,这是我迄今为止依然坚持的原因,即使这是 2022 年的寒秋

反思了下:

  1. 博客还是要尽可能简洁
  2. 已有的结论尽可能少写,实验得出的结论可分析一下
  3. 加强实践,代码为先
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值