前言

正在成都面试Java后端开发,有老板缺人可以M一下~

问题描述

Java笔试题出现这个问题概率还挺大,手写一下两个线程交替打印一组序列或者按顺序两组序列,本文以后者为例。线程1打印1,2,3,4,5,线程2打印a,b,c,d,e。问题本质就是一个简单的线程同步实现,同步的操作是打印

解决思路

两个线程中run方法(Runnable对象)主体是一个循环,循环内部是同步代码,所以在程序外需要一个共用的🔒对象。可以使用synchronized语句块(1.4提供)结合notify和wait机制实现,但是存在后一个打印线程阻塞的问题(因为这个线程最后一次释放🔒--wait之后没有地方调用notify/notifyAll来通知它再次获取🔒)导致程序阻塞。所以这里的解法使用Lock和Condition(1.5)的实现办法

代码

/**
这里实现的是三个线程同时参与打印三元组的序列,和本题考察点相同
*/
public static void main(String[] args) {
        Lock lock = new ReentrantLock(); // 使用ReentrantLock,即一个线程可以重复获得🔒
        Condition rotate = lock.newCondition(); // 一个Lock实例可以有多个条件实例,这里只需要通过newCondition来获得一个
        final AtomicInteger seq = new AtomicInteger(1); // 协助判断条件,lambda中使用的外部变量必须是final的,普通的Integer也可以,因为这个变量的操作是在同步代码内

        new Thread(() -> {
            int i = 0;
            while (i <= 5) {
                lock.lock(); // 加锁
                try {
                    while (!(seq.get() % 3 == 1)) {
                        rotate.await(); // 如果当前不该它打印,则即使获得🔒,也应该交出去并继续等待。这里相当于等待的是条件而不是🔒
                    }
                    System.out.printf("<%d, ", i++);
                    seq.incrementAndGet(); // 修改条件的内容
                    rotate.signalAll(); // 通知其它线程获取🔒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock(); // 推荐写法,在finally语句块中释放🔒
                }
            }
        }).start();

        new Thread(() -> {
            int i = 5;
            while (i >= 0) {
                lock.lock();
                try {
                    while (!(seq.get() % 3 == 2)) {
                        rotate.await();
                    }
                    System.out.printf("%d, ", i--);
                    seq.incrementAndGet();
                    rotate.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }).start();

        new Thread(() -> {
            int i = 6;
            while (i <= 10) {
                lock.lock();
                try {
                    while (!(seq.get() % 3 == 0)) {
                        rotate.await();
                    }
                    System.out.printf("%d>", i--);
                    seq.incrementAndGet();
                    rotate.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        }).start();
    }

备注

参考书籍 《Java Core》ed11,竞争条件部分

题目虽然不难,但是这应该是解决经典的同步问题的基本思路和实现,记录一下

posted on 2021-04-13 17:37  老鼠不上树  阅读(126)  评论(0)    收藏  举报