java双线程交替打印1-100的数字

第一版代码

Thread threadOdd = new Thread(() -> {
for (int i = 1; i <= 99; i+=2){
        synchronized (sharedThing){
            System.out.println(Thread.currentThread().getName() + " " + i);
            try {
                sharedThing.wait();
                sharedThing.notify();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
});

Thread threadEven = new Thread(() -> {
for (int i = 2; i <= 100; i += 2) {
    synchronized (sharedThing) {
        System.out.println(Thread.currentThread().getName() + " " + i);
        sharedThing.notify();
        try {
            sharedThing.wait();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
});

threadOdd.start();
Thread.sleep(1000);
threadEven.start();`

image

效果看起来还可以,但是稍微改动一下threadOdd就会出现问题,比如这样:

Thread threadOdd = new Thread(() -> {
for (int i = 1; i <= 99; i+=2){
        synchronized (sharedThing){
            System.out.println(Thread.currentThread().getName() + " " + i);
            try {
                sharedThing.wait();
                sharedThing.notify();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
});

结果为:
image

threadOdd抢占共享资源的过程被延长了,导致threadEven先占用了资源,threadOdd无法被唤醒,死锁了

所以修改一下,加入奇数偶数校验,保证打印奇数线程只打印奇数,偶数线程只打印偶数

让两个线程严格按照顺序执行

第二版代码

    Thread threadOdd = new Thread(() -> {
        while (cur < 100){
            synchronized (sharedThing){
                if(cur % 2 == 1){
                    System.out.println(Thread.currentThread().getName() + ":" + cur);
                    cur += 1;
                    try {
                        sharedThing.wait();
                        sharedThing.notify();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    });

    Thread threadEven = new Thread(() -> {
        while (cur < 100){
            synchronized (sharedThing){
                if(cur % 2 == 0){
                    sharedThing.notify();
                    System.out.println(Thread.currentThread().getName() + ":" + cur);
                    cur += 1;
                    try {
                        sharedThing.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    });

    threadOdd.start();
    threadEven.start();
}

效果如下

使用ReentrantLock和Condition的代码

奇数线程准备奇数数字1,3,5,... ,49

偶数线程准备偶数数字2,4,6, ... ,50

condition负责保证奇数偶数打印的顺序

public static void reenTrantLockPrint(){
        ReentrantLock reentrantLock = new ReentrantLock();
        Condition oddCondition = reentrantLock.newCondition();
        Condition evenCondition = reentrantLock.newCondition();
        new Thread(() -> {
            int i = 1;
            while(i <= 50){
                reentrantLock.lock();
                if(i % 2 == 1){
                    System.out.println(Thread.currentThread().getName() + " 打印" + i);
                    evenCondition.signal();
                    i+=2;
                    try {
                        oddCondition.await();
                        reentrantLock.unlock();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        },"odd").start();

        new Thread(() -> {
            int i = 2;
            while(i <= 50){
                reentrantLock.lock();
                System.out.println(Thread.currentThread().getName() + " 打印" + i);
                oddCondition.signal();
                i+=2;
                try {
                    evenCondition.await();
                    reentrantLock.unlock();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        },"even").start();
    }

效果

image

才疏学浅,如果有错误或不准确的地方,欢迎大家指出

posted @   卡利的亲爹  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示