zoukankan      html  css  js  c++  java
  • 线程间通信

    传送门

    https://blog.nowcoder.net/n/29dfac7b41b54be180aa4c2eb68dacb6

    问题描述

    有4个线程和1个公共的字符数组。线程1的功能就是向数组输出A,线程2的功能就是向字符输出B,线程3的功能就是向数组输出C,线程4的功能就是向数组输出D。要求按顺序向数组赋值ABCDABCDABCD,ABCD的个数由线程函数1的参数指定。

    示例1
    
    输入
    10
    
    输出
    ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD

    解题思路

     

    线程交替打印

    线程交替打印需要用到线程通信的知识。其他的方法我不太了解,首先想到的就是用Condition来实现线程之间的通信。刚开始写好代码,本地运行,多组测试结果什么的都正确,但是一到线上运行,打印的结果就是乱的,之前从来没有遇到过这种情况,想了我一个多小时。最后突然想到测试用例输入的时候和在本地运行输入的情况有点不一样。因为需要多组测试,所以需要定义一个while(scanner.hasNext()){...}的循环体。本地测试由于是我们手动输入的,在下一次输入之前,前一次的打印结果就已经全部结束了(四个线程已经运行结束)。但是线上是机器测试的,可能前一次的测试还没打印结束,下一次的测试又开始了,所以会导致两次的测试数据会穿插在一起。
    知道了原因,就好办了,只要做到每一次测试打印结束后while(){}循环才能结束,首先想到的就是用CountdownLatch。每次while循环开始就定义一个countdownLatch(4),每个线程结束后计数器就减一,减到0后再进行下一组数据的测试。
    代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    import java.util.Scanner;
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
     
    /**
     * 多线程,线程交替打印ABCDABCD
     */
    public class Test49 {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            while (scanner.hasNext()) {
                int n = scanner.nextInt();
                CountDownLatch countDownLatch = new CountDownLatch(4);
                AlternativePrint alternativePrint = new AlternativePrint();
                //创建四个线程
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            for (int i = 0; i < n; i++) {
                                alternativePrint.printA();
                            }
                        finally {
                            countDownLatch.countDown();
                        }
                    }
                }).start();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            for (int i = 0; i < n; i++) {
                                alternativePrint.printB();
                            }
                        finally {
                            countDownLatch.countDown();
                        }
                    }
                }).start();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            for (int i = 0; i < n; i++) {
                                alternativePrint.printC();
                            }
                        finally {
                            countDownLatch.countDown();
                        }
                    }
                }).start();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            for (int i = 0; i < n; i++) {
                                alternativePrint.printD();
                            }
                        finally {
                            countDownLatch.countDown();
                        }
                    }
                }).start();
                try {
                    countDownLatch.await();
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println();
            }
        }
    }
     
    class AlternativePrint {
        private Lock lock = new ReentrantLock();
        private Condition conditionA = lock.newCondition();
        private Condition conditionB = lock.newCondition();
        private Condition conditionC = lock.newCondition();
        private Condition conditionD = lock.newCondition();
        private int number = 1;
     
        void printA() {
            lock.lock();
            try {
                if (number != 1) {
                    conditionA.await();
                }
                System.out.print("A");
                //"A"打印结束,标记置为2,并唤醒打印"B"的线程
                number = 2;
                conditionB.signal();
            catch (InterruptedException e) {
                e.printStackTrace();
            finally {
                lock.unlock();
            }
        }
     
        void printB() {
            lock.lock();
            try {
                if (number != 2) {
                    conditionB.await();
                }
                System.out.print("B");
                //"B"打印结束,标记置为3,并唤醒打印"C"的线程
                number = 3;
                conditionC.signal();
            catch (InterruptedException e) {
                e.printStackTrace();
            finally {
                lock.unlock();
            }
        }
     
        void printC() {
            lock.lock();
            try {
                if (number != 3) {
                    conditionC.await();
                }
                System.out.print("C");
                //"C"打印结束,标记置为4,并唤醒打印"D"的线程
                number = 4;
                conditionD.signal();
            catch (InterruptedException e) {
                e.printStackTrace();
            finally {
                lock.unlock();
            }
        }
     
        void printD() {
            lock.lock();
            try {
                if (number != 4) {
                    conditionD.await();
                }
                System.out.print("D");
                //"D"打印结束,标记置为1,并唤醒打印"A"的线程
                number = 1;
                conditionA.signal();
            catch (InterruptedException e) {
                e.printStackTrace();
            finally {
                lock.unlock();
            }
        }
    }
  • 相关阅读:
    软件测试常见概念
    Apollo简介及工作原理
    bug的编写技巧与级别划分
    native与H5优缺点及H5测试
    优惠券测试
    go语言-for循环
    go语言-流程控制--if
    go语言-二进制与位运算
    cookie和session
    AJAX
  • 原文地址:https://www.cnblogs.com/yanghaolie/p/13817791.html
Copyright © 2011-2022 走看看