多线程: 如何实现多个线程按序打印?

题目

提供一个类

public class Foo {
    private static void printA() {
                System.out.print("A");
    }
    private static void printB() {
                System.out.print("B");
    }
    private static void printC() {
                System.out.print("C");
    }

会有3个线程分别调用printA(),printB(),printC()方法;
编程实现输出结果是ABC.

透过问题看本质:

要实现按序打印,也就是printB要在printA执行之后执行, printC要在printB执行之后执行;

1.利用wait()和notifyAll()

    private static final Object obj = new Object();
    private static int type = 1;

    private static void printA() {
        synchronized (obj) {

            if (type == 1) {
                System.out.print("A");
                type = 2;
                //更新type后唤醒其他线程
                obj.notifyAll();
            }
        }
    }

    private static void printB() throws InterruptedException {
        synchronized (obj) {

            while (type != 2) {
                //当type!=2时,阻塞当前线程
                obj.wait();
            }
            if (type == 2) {
                System.out.print("B");
                type = 3;
                //更新type后唤醒其他线程
                obj.notifyAll();
            }
        }
    }

    private static void printC() throws InterruptedException {
        synchronized (obj) {

            while (type != 3) {
                //当type!=3时,阻塞当前线程
                obj.wait();
            }
            if (type == 3) {
                System.out.print("C");
            }
        }
    }

    @Test
    public void test1() throws InterruptedException {

        new Thread(new Runnable() {
            @Override
            public void run() {
                printA();
            }
        }).start();
        new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                printB();
            }
        }).start();
        new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                printC();
            }
        }).start();
        Thread.sleep(3000);
    }

思路:

当线程A没执行之前,利用wait()方法阻塞B, C线程; 线程A执行完成之后,更新type值并利用notifyAll()唤醒B,C线程, 使得B线程得以往下执行(此时C线程被唤醒后因为type !=3,因此会被wait()方法再次阻塞);B线程执行完成后更新type值并唤醒线程C,使得线程C得以往下执行;

2. 利用CountDownLatch

//初始化两个值为1的计数器
    private static CountDownLatch countDownLatchB = new CountDownLatch(1);
    private static CountDownLatch countDownLatchC = new CountDownLatch(1);
    private static void printA2() {
        System.out.print("A");
        countDownLatchB.countDown();//将计数器值减1
    }

    private static void printB2() throws InterruptedException {
        countDownLatchB.await();//当值不为0时,当前线程会被阻塞
        System.out.print("B");
        countDownLatchC.countDown();
    }

    private static void printC2() throws InterruptedException {
        countDownLatchC.await();
        System.out.print("C");
    }

    @Test
    public void test2() throws InterruptedException {

        new Thread(new Runnable() {
            @Override
            public void run() {
                printA2();
            }
        }).start();
        new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                printB2();
            }
        }).start();
        new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                printC2();
            }
        }).start();
        Thread.sleep(3000);
    }

CountDownLatch:

CountDownLatch是一个计数器, 它在初始化时要输入一个数值型的参数作为计数器的值; 其有两个主要的方法,await()和countDown(); countDown()方法会将计数器的值减1;await()方法是:当计数器值不为0时,阻塞当前线程;计数器值为0时,唤醒当前线程; 该篇文章有对CountDownLatch的详细解析:如何实现某个线程在其他线程执行完毕之后再执行

思路:

利用CountDownLatch,创建两个值为1的计数器;分别用来阻塞B,C线程;当线程A执行完成之后,将B线程的计数器减1,使其计数器值为0,从而B线程得以唤醒;同理,B线程执行完成之后会唤醒C线程;从而达到按序执行的效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值