楼主今天在面经上看到这个题,挺有意思,小小的题目对多线程的考量还挺多。大部分同学都会使用 synchronized 来实现。

楼主今天带来另外两种优化实现,让你面试的时候,傲视群雄!

synchronized实现

class ThreadPrintDemo2 {public static void main(String[] args) {final ThreadPrintDemo2 demo2 = new ThreadPrintDemo2();Thread t1 = new Thread(demo2::print1);Thread t2 = new Thread(demo2::print2);t1.start();t2.start();}public synchronized void print2() {for (int i = 1; i <= 100; i += 2) {System.out.println(i);this.notify();try {this.wait();Thread.sleep(100);} catch (InterruptedException e) {}}}public synchronized void print1() {for (int i = 0; i <= 100; i += 2) {System.out.println(i);this.notify();try {this.wait();Thread.sleep(100);} catch (InterruptedException e) {}}}
}

通过 synchronized 同步两个方法,每次只能有一个线程进入,每打印一个数,就释放锁,另一个线程进入,拿到锁,打印,唤醒另一个线程,然后挂起自己。循环反复,实现了一个最基本的打印功能。面试常问的:Synchronized 有几种用法。

但,如果你这么写,面试官肯定是不满意的。楼主将介绍一种更好的实现。

CAS 实现

public class ThreadPrintDemo {static AtomicInteger cxsNum = new AtomicInteger(0);static volatile boolean flag = false;public static void main(String[] args) {Thread t1 = new Thread(() -> {for (; 100 > cxsNum.get(); ) {if (!flag && (cxsNum.get() == 0 || cxsNum.incrementAndGet() % 2 == 0)) {try {Thread.sleep(100);} catch (InterruptedException e) {}System.out.println(cxsNum.get());flag = true;}}});Thread t2 = new Thread(() -> {for (; 100 > cxsNum.get(); ) {if (flag && (cxsNum.incrementAndGet() % 2 != 0)) {try {Thread.sleep(100);} catch (InterruptedException e) {}System.out.println(cxsNum.get());flag = false;}}});t1.start();t2.start();}
}

我们通过使用 CAS,避免线程的上下文切换,然后呢,使用一个 volatile 的 boolean 变量,保证不会出现可见性问题,记住,这个 flag 一定要是 volatile 的,如果不是,可能你的程序运行起来没问题,但最终一定会出问题,而且面试官会立马鄙视你。

这样就消除了使用 synchronized 导致的上下文切换带来的损耗,性能更好。相信,如果你面试的时候,这么写,面试官肯定很满意。

但,我们还有性能更好的。

volatile实现

class ThreadPrintDemo3{static volatile int num = 0;static volatile boolean flag = false;public static void main(String[] args) {Thread t1 = new Thread(() -> {for (; 100 > num; ) {if (!flag && (num == 0 || ++num % 2 == 0)) {try {Thread.sleep(100);} catch (InterruptedException e) {}System.out.println(num);flag = true;}}});Thread t2 = new Thread(() -> {for (; 100 > num; ) {if (flag && (++num % 2 != 0)) {try {Thread.sleep(100);} catch (InterruptedException e) {}System.out.println(num);flag = false;}}});t1.start();t2.start();}
}

我们使用 volatile 变量代替 CAS 变量,减轻使用 CAS 的消耗,注意,这里 ++num 不是原子的,但不妨碍,因为有 flag 变量控制。而 num 必须是 volatile 的,如果不是,会导致可见性问题。

到这里,如果你面试的时候这么写,那么,offer 就不远啦!哈哈

两个线程如何交替执行,一个输出偶数一个输出奇数?相关推荐

  1. 【java】两个线程如何交替执行,一个输出偶数一个输出奇数?

    楼主今天在面经上看到这个题,挺有意思,小小的题目对多线程的考量还挺多.大部分同学都会使用 synchronized 来实现. 楼主今天带来另外两种优化实现,让你面试的时候,傲视群雄! synchron ...

  2. 简单创建两个线程,交替输出内容

    简单创建两个线程,交替输出内容 package p1; public class Java_1 {//*********Found**********public static void main ( ...

  3. 【完整代码】使用Semaphore实现线程的交替执行打印 A1B2C3D4E5

    import java.util.concurrent.Semaphore;/**使用Semaphore实现线程的交替执行打印 A1B2...Semaphore 基于AQS(内部维护了一个队列)可以用 ...

  4. 让两个线程有先后执行顺序

    让两个线程有先后执行顺序 public class Join1_One extends Thread {public void run(){System.out.println(Thread.curr ...

  5. 设计两个个线程模拟存取款操作,其中一个线程每次随机存1~1000元钱,另外一个线程取1-1000元钱,如果余额不足,则取款失败,提示余额不足。写出程序(考虑并发问题)。

    设计两个个线程模拟存取款操作,其中一个线程每次随机存1~1000元钱, 另外一个线程取1-1000元钱,如果余额不足,则取款失败,提示余额不足. 写出程序(考虑并发问题). import java.u ...

  6. c语言输入一批正整数 求其中的偶数和,编程,输入一批整数,先求出其中的偶数和及奇数和,然后输出偶数和与奇数和的差...

    设计一个程序,要求输入三个整数,能求出其中最大的数并输出 #includeintmain{inti;inta1,a2,a3;printf("输入三个数:\n");scanf(&qu ...

  7. 进程有一个全局变量 i,还有有两个线程。i++ 在两个线程里边分别执行 100 次,能得到的最大值和最小值分别是多少?

    转自https://blog.csdn.net/biubiu741/article/details/77990592 多核CPU最小值为2,最大值200. 假设两个线程的执行步骤如下: 1. 线程A执 ...

  8. python输出偶数_Python 判断奇数偶数的方法

    Python 判断奇数偶数的方法 以下实例用于判断一个数字是否为奇数或偶数: # -*- coding: UTF-8 -*- # Filename : test.py # Python 判断奇数偶数 ...

  9. Java-JUC(十):线程按序交替执行

    问题: 有a.b.c三个线程,使得它们按照abc依次执行10次. 实现: package com.dx.juc.test;import java.util.concurrent.locks.Condi ...

最新文章

  1. python下什么-python要下什么
  2. A、B、C、D四个字母,能组成多少个互不相同且无重复三位组合
  3. Windows建立目录软连接
  4. 使用TWebBrowser组件保存网页为html和mht文件 收藏
  5. android gradle自定义钉钉群提醒
  6. docker run命令详解
  7. knockoutJS学习笔记01:从拼接字符串到编写模板引擎
  8. allegro下快捷键设置[转贴]
  9. 与40mhz信道不兼容设置_物理信道发射功率
  10. java ajax data_jquery ajax 方法中传递的data参数,如何在java类中获取
  11. python qt信号在qml 的使用_QML使用Python的函数过程解析
  12. mysql 闪回查询 sql_利用闪回查看Oracle表历史时刻数据
  13. DotText源码阅读(2)-工程、数据库表结构
  14. 使用CDN后网页无法访问怎么解决
  15. Java Grammar(二):运算符
  16. WIN10计算机用户怎么改名,win10怎么改名字_win10怎么改用户名字
  17. 【C#基础】输入一个字符,判定它是什么类型的字符(大写字母,小写字母,数字或者其它字符)
  18. 微信服务号的六大价值有哪些
  19. 代理商分销订货系统(电脑、H5、小程序、APP)多端全套源码
  20. https证书可以保护二级域名吗

热门文章

  1. Erlang vs Java memory architecture (zz)
  2. C# 创建、部署和调用WebService的示例
  3. ElasticSearch---------------------Elasticsearch Clients---------------------JAVA API
  4. 创建支持nginx服务的docker镜像
  5. 利用apache-commons-fileupload写jsp上传文件
  6. 基于OpenCV的findContours查找图像连通域,并进行排序
  7. c与c++中struct区别
  8. php判断完整数,PHP的几个常用数字判断函数代码
  9. anaconda中的python如何进行关联分析_浅析python,PyCharm,Anaconda三者之间的关系
  10. 格式说明_法律文书:公司单位民事起诉状格式范本及说明,最高人民法院2016...