经典面试题——两个线程交替打印奇数和偶数
2019-08-16 09:39:08来源:博客园 阅读 ()
经典面试题——两个线程交替打印奇数和偶数
前提
今天下班时候和同事聊天偶然听到面试题“两个线程交替打印奇数和偶数”的实现,这里做一个复盘。
复盘
场景一:线程A打印奇数,线程B打印偶数,线程A和线程B交替打印,使用对象监视器实现。
场景二:线程A打印奇数,线程B打印偶数,线程A和线程B交替打印,使用JDK提供的并发类库实现。
这两个场景中,场景一是一种比较古老的同步方式,本质由JVM实现;场景二是JDK1.5引入JUC包之后简化了并发编程的前提下的更简便的实现。下面针对两个场景做对应的实现。
场景一
场景一中,线程A和线程B交替打印奇数和偶数,使用对象监视器实现,通俗来说:线程A或线程B只要有一者竞争锁成功,就打印++i,通知其他线程从等待集合中释放,然后自身线程加入等待集合并且释放锁即可。
public class OddEvenPrinter { private final Object monitor = new Object(); private final int limit; private volatile int count; public OddEvenPrinter(int limit, int initCount) { this.limit = limit; this.count = initCount; } public void print() { synchronized (monitor) { while (count < limit) { try { System.out.println(String.format("线程[%s]打印数字:%d", Thread.currentThread().getName(), ++count)); monitor.notifyAll(); monitor.wait(); } catch (InterruptedException e) { //ignore } } } } public static void main(String[] args) throws Exception { OddEvenPrinter printer = new OddEvenPrinter(10, 0); Thread thread1 = new Thread(printer::print, "thread-1"); Thread thread2 = new Thread(printer::print, "thread-2"); thread1.start(); thread2.start(); Thread.sleep(Integer.MAX_VALUE); } }
执行后的输出结果:
线程[thread-1]打印数字:1 线程[thread-2]打印数字:2 线程[thread-1]打印数字:3 线程[thread-2]打印数字:4 线程[thread-1]打印数字:5 线程[thread-2]打印数字:6 线程[thread-1]打印数字:7 线程[thread-2]打印数字:8 线程[thread-1]打印数字:9 线程[thread-2]打印数字:10
场景二
场景二中,如果需要使用JUC中提供的并发类库,可以考虑和对象监视器功能接近的可重入锁ReentrantLock
。具体代码如下:
public class OddEvenPrinterEx { private final ReentrantLock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private final int limit; private volatile int count; public OddEvenPrinterEx(int limit, int initCount) { this.limit = limit; this.count = initCount; } public void print() { lock.lock(); try { while (count < limit){ System.out.println(String.format("线程[%s]打印数字:%d", Thread.currentThread().getName(), ++count)); condition.signalAll(); try { condition.await(); } catch (InterruptedException e) { //ignore } } } finally { lock.unlock(); } } public static void main(String[] args) throws Exception { OddEvenPrinterEx printer = new OddEvenPrinterEx(10, 0); Thread thread1 = new Thread(printer::print, "thread-1"); Thread thread2 = new Thread(printer::print, "thread-2"); thread1.start(); thread2.start(); Thread.sleep(Integer.MAX_VALUE); } }
执行后的输出结果:
线程[thread-2]打印数字:1 线程[thread-1]打印数字:2 线程[thread-2]打印数字:3 线程[thread-1]打印数字:4 线程[thread-2]打印数字:5 线程[thread-1]打印数字:6 线程[thread-2]打印数字:7 线程[thread-1]打印数字:8 线程[thread-2]打印数字:9 线程[thread-1]打印数字:10
眼尖的可能看到这里是先由thread-2打印奇数,然后thread-1打印偶数,这个和同步器框架的等待队列以及同步队列的竞争有关。
小结
这个问题有很多种解决思路,但是目前笔者没想到无锁实现方案。很多现成的(参考多个博客)方案里面都是使用各种多重同步或者加锁,其实意义是不大,实际上要理解对象监视器和同步器框架AQS的一些原理,那么实现起来自然比较简单。
写在最后
- 第一:看完点赞,感谢您的认可;
- ...
- 第二:随手转发,分享知识,让更多人学习到;
- ...
- 第三:记得点关注,每天更新的!!!
- ...
原文链接:https://www.cnblogs.com/Java-no-1/p/11119746.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- JVM常见面试题解析 2020-06-11
- 送你一份年薪百万的抖音Java岗内部面试题 2020-06-09
- 总结一些 Java 相关笔试、面试题,万一用上了呢 (=_=) -- 基 2020-06-08
- 最强Dubbo面试题,附带超级详细答案 2020-06-06
- 2020Java面试题及答案,命中率高达90% 2020-06-05
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash