面试题:三个线程按顺序打印 ABCABC

网站建设3年前发布
10 0 0

小伙伴们好呀,最近在重新复习,整理自己的知识库,偶然看到这道面试题:三个线程按顺序打印 ABCABC,尝试着做一下,才发现自己对线程还有好多地方不懂,蓝瘦…… ,很明显,这里就涉及线程间相互通信的知识了。,而相互通信的难点就是要控制好,阻塞和唤醒的时机。,2023030613135759a5e2e17d65134d67b88792d809ec3b201a4d631,线程 A 先拿到资源 c,再拿资源 a ,[a 执行完后释放,并唤醒等待资源 a]  的 线程 B 线程 B 先拿到资源 a,再拿资源 b ,[b 执行完后释放,并唤醒等待资源 b]  的 线程 C 线程 C 先拿到资源 b,再拿资源 c ,[c 执行完后释放,并唤醒等待资源 c]  的 线程 A,所以得有 三个 共享资源 abc 来达到互斥条件,Synchronized 还是 ReentrantLock 都得建立 三个共享资源,20230306131358538b56425e6ddca343157881cc22132976e86d392,使用 LockSupport ,如果要像上面这样子的思路去解答,就得注意 线程相互引用行成的循环依赖问题,这里借用 Spring 的思路 用 Map 巧妙化解。 ,或者做法2 通过 外部的成员变量,不断地去判断,unpark 线程 a b c,Synchronized 方式,这里我借用 countDownLatch 去控制线程的启动流程,尽量不使用 Thread.sleep() 来实现,拿捏线程的执行,通信步骤。,写这个的时候,除了一开始思路不清晰外,还出现一个小状况,就是 程序执行完卡住了。,20230306131358b4a9a12664a7cf6d00b749c1db30fa2f41bab0858,debug 发现线程 B C 还在 wait 状态,这是写时候容易疏忽的。,要记得在循环外再次唤醒其他线程,让他们走完方法。,20230306131505e60b9d43306b88014aa247de6d6743b12996b0441,ReentrantLock 方式,Synchronized 会了之后,这个也很简单了。,就是上锁的地方换成 lock.lock();,把三个共享资源换成 lock.newCondition();,然后思考一下阻塞条件 condition1.await() 。,毕竟 打印 和 唤醒 的操作总是在一起的。,20230306131505e98312e33d51084e459817c21e1ce4db6d0b0d412,Semaphore 我也写了,但是感觉不太适合,毕竟它的作用是用来控制并发线程数的,我直接创建三个 Semaphore  总觉得怪怪的。,LockSupport 方式,这里我写了两种方法,LockSupport 我也是第一次用,它使用起来也很方便,就单纯的 阻塞和唤醒线程 ,对应 park 和 unPark 方法。,它不要求你像 wait 那样子,必须写在 Synchronized 代码块里,被 Monitor 监视才行。,但同时,也意味着你必须控制好这个 锁的范围 。,你可以自由阻塞代码,在具备某个条件时,唤醒特定的线程,让它继续执行。,实际上,上面 ReentrantLock 中的 Condition await 方法,底层就是调用 LockSupport 的 park 方法。,这也是我开头说的通信大致分为两种方式的原因。,方法一中,我是用 parkNanos 阻塞一段时间,然后就继续运行,也算是取巧不用 Thread.Sleep 了吧,方法二 我比较喜欢,思路也是同开头两种,打印完唤醒其他线程。

© 版权声明

相关文章