两个线程交替打印字符

从别处看来得题目,觉得蛮有意思,记录一下;

已知数组 A 内容为1、2、3、4...52,数组 B 内容为 26 个英文字母,使用两个线程分别输入两个数组,然后使程序运行打印内容为 12a34b56c78e... 的规律,请给出代码实现?

这个问题的核心就是两个线程交替等待执行,对应到java中就是线程之间的协同;首先用第一种实现,自旋锁的方式:

首先看一种错误的方式:

先是打印数值类型的类:

public class PrintNumber implements Runnable {

    private int number[] = {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};

    private Boolean isNumber;

    public PrintNumber(Boolean isNumber) {
        this.isNumber = isNumber;
    }

    @Override
    public void run() {
        int j = 0;
        for (int i = 0; i < number.length; i++) {
            while (!isNumber) {
                Thread.yield();
            }
            j++;
            System.out.print(number[i]);
            if (j == 2) {
                isNumber = false;
                j = 0;
            }
        }
        isNumber = false;
    }
}

然后是打印字符类型的类

public class PrintChar implements Runnable {

    private char charArray[] = {'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'};

    private boolean isNumber;

    public PrintChar(boolean isNumber) {
        this.isNumber = isNumber;
    }

    @Override
    public void run() {
        for (int i = 0; i < charArray.length; i++) {
            while (isNumber) {
                Thread.yield();
            }
            System.out.print(charArray[i]);
            isNumber = true;
        }
        isNumber = true;
    }

    public static void main(String[] args) {
        Boolean isNumber = true;
        Thread thread1 = new Thread(new PrintNumber(isNumber));
        Thread thread2 = new Thread(new PrintChar(isNumber));
        thread1.start();
        thread2.start();
    }
}

执行结果发现,只输入了1 2;原因在于定义的变量isNumber是每个线程中的变量值是不一样的,没有内存的可见性,所以数值类型执行了2次之后不执行了,字符类型的从一开始就不会执行,每个线程是自己的变量值;所以要修改成AtomicBoolean;修改后的代码如下所示

public class PrintNumber implements Runnable {

    private int number[] = {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};

    private AtomicBoolean isNumber;

    public PrintNumber(AtomicBoolean isNumber) {
        this.isNumber = isNumber;
    }

    @Override
    public void run() {
        int j = 0;
        for (int i = 0; i < number.length; i++) {
            while (!isNumber.get()) {
                Thread.yield();
            }
            j++;
            System.out.print(number[i]);
            if (j == 2) {
                isNumber.set(false);
                j = 0;
            }
        }
        isNumber.set(false);
    }
}

public class PrintChar implements Runnable {

    private char charArray[] = {'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'};

    private AtomicBoolean isNumber;

    public PrintChar(AtomicBoolean isNumber) {
        this.isNumber = isNumber;
    }

    @Override
    public void run() {
        for (int i = 0; i < charArray.length; i++) {
            while (isNumber.get()) {
                Thread.yield();
            }
            System.out.print(charArray[i]);
            isNumber.set(true);
        }
        isNumber.set(true);
    }

    public static void main(String[] args) {
        AtomicBoolean isNumber = new AtomicBoolean(true);
        Thread thread1 = new Thread(new PrintNumber(isNumber));
        Thread thread2 = new Thread(new PrintChar(isNumber));
        thread1.start();
        thread2.start();
    }
}

基本思路就是,循环打印出数值和字符,然后在分别循环2次和一次之后,设置是否是数值类型的boolean,每次在打印之前判断是否满足条件,不满足就一直循环等待;

2.采用LockSupport的方式

LockSupport使用park和unpark来实现线程的阻塞和唤醒,只有一个许可可以使用,如果这个许可没有被占用,那么当前线程继续执行,如果许可被占用,线程处于阻塞状态,直到获取到许可;代码如下所示

public class LockSupportPrintNumber extends Thread {

    private int number[] = {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};

    private Thread thread;

    public void setThread(Thread thread) {
        this.thread = thread;
    }

    @Override
    public void run() {
        int count = 0;

        for (int i = 0; i < number.length; i++) {
            if (count == 2) {
                count = 0;
                LockSupport.unpark(thread);
                LockSupport.park();
            }
            System.out.print(number[i]);
            count++;
        }
        LockSupport.unpark(thread);
    }
}

public class LockSupportPrintChar extends Thread {

    private char charArray[] = {'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'};

    private Thread thread;

    public void setThread(Thread thread) {
        this.thread = thread;
    }

    @Override
    public void run() {
        int count = 0;
        LockSupport.park();
        for (int i = 0; i < charArray.length; i++) {
            System.out.print(charArray[i]);
            count++;
            if (count == 1) {
                count = 0;
                LockSupport.unpark(thread);
                LockSupport.park();
            }
        }
        LockSupport.unpark(thread);
    }
}

 public static void main(String[] args) {
        LockSupportPrintChar thread2 = new LockSupportPrintChar();
        LockSupportPrintNumber thread1 = new LockSupportPrintNumber();
        thread1.setThread(thread2);
        thread2.setThread(thread1);
        thread1.start();
        thread2.start();
    }

参考文章:

https://mp.weixin.qq.com/s/hqq_IFS2oSGOaulUievWnQ

猜你喜欢

转载自blog.csdn.net/xiaoguangtouqiang/article/details/81321119