多线程按序打印之使用CountDownLatch遇到的问题及解决

多线程的交替打印问题(如两个线程循环打印1到100、三个线程循环打印a到z等都可以使用CountDownLatch解决),这里记录我使用CountDownLatch遇到的一个bug。
先看使用两个线程交替打印1-100

public class PrintaToz {
    static int i = 0;
    public static void main(String[] args) {
       test();
    }
    static void test(){

        CountDownLatch c1 = new CountDownLatch(2);
        Thread t1 = new Thread(() -> {
            int count = 26;
            while (i < count){
//              if(i % 2 == 0 && i < count){
                if(i % 2 == 0){
                    char tar = (char) (i + 'a');
                    System.out.println(tar);
                    i++;
                }
            }
            c1.countDown();
        },"t1");

        Thread t2 = new Thread(() -> {
            int count = 26;
            while (i < count){
//              if(i % 2 == 1 && i < count){
                if(i % 2 == 1){
                    char tar = (char) (i + 'a');
                    System.out.println(tar);
                    i++;
                }
            }
            c1.countDown();
        },"t2");
        t1.start();
        t2.start();
        try {
            c1.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

多执行几次,反复观察程序输出,会发现有时会输出27个字符,多输出了ASCII中字符z的后一位{

a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
{

为什么呢?
考虑当i = 25时,第一个线程判断i < count不成立,进入内部的if判断,但如果进入if前第二个线程将i改为了26,那么判断成立,因此会多输出一个字符。
如何解决呢,我的解决方法是在if内再判断一次while中的条件,是否有更好的方案呢,期待你的答案。
顺便提一下,这里两个线程同时操作变量i却没有线程安全问题,这是因为两个线程操作i的时间是错开的,因此是线程安全的。
此外,改方法可以简单改动实现变种的交替打印问题,如三个线程分别打印A B循环100次可以采用下面方式实现。

public class PrintABC {
    public static void main(String[] args) {
        printAB();
    }
    /**
     * 两个线程循环打印A,B 100次
     */
    static int i = 0;
    static void printAB(){
        CountDownLatch c = new CountDownLatch(2);
        Thread t1 = new Thread(() ->{
            int total = 100*2;
            while (i < total){
                if(i % 2 == 0){
                    System.out.print(Thread.currentThread().getName()+" ");
                    System.out.println("A");
                    i++;
                }
            }
            c.countDown();
        },"t1");
        Thread t2 = new Thread(() ->{
            int total = 100*2;
            while (i < total){
                if(i % 2 == 1){
                    System.out.print(Thread.currentThread().getName()+" ");
                    System.out.println("B");
                    i++;
                }
            }
            c.countDown();
        },"t2");
        t1.start();
        t2.start();
        try {
            c.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值