08 两个线程交替打印121212...
来源:互联网 发布:淘宝c店直播运营 编辑:程序博客网 时间:2024/05/29 14:40
前言
唉, 忧伤..
问题描述
今天 无意间看到了这样一个问题, 两个线程, 一个打印”1”, 另外的一个打印”2”, 写出程序实现如下输出”121212…”
思路
这个问题, 我以前也没有碰到过, 看到这个问题, 我的第一想法是, 两个线程
1. 让线程2先wait, 然后 线程1执行打印业务之后, 叫醒线程2, 然后 自己也wait
2. 然后 再”线程1 ‘变成’ 线程2, 线程2 ‘变成’ 线程1”, 然后 在走上面的业务[这里 如此说明, 仅仅是为了突出两个线程的业务基本上是相似的, 因此 可以共用一份代码]
3. 周期性的执行
Code01
然后 我写出了我的第一个版本的实现, 如下 :
// 两条线程, 打印出121212 public static void main(String[] args) { MyThread t01 = new MyThread(1), t02 = new MyThread(t01, 2); t01.other = t02; t01.start();// Tools.sleep(1 * 1000); t02.start(); } // MyThread static class MyThread extends Thread { MyThread other; private Object lock; private int output; // 初始化 public MyThread(MyThread other, int output) { this.other = other; this.lock = new Object(); this.output = output; } public MyThread(int output) { this(null, output); } @Override public void run() { if(output == 2) { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } while(true) { System.out.println(output); synchronized (other.lock) { other.lock.notify(); } synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
这样看似正确了, 但是 多线程的场景下面, 你永远不能使用单线程的思维来思考
呵呵 存在很明显的几个问题[当然 如果存在还有其他问题, 大家可以分享一下], 看到了么
1. 试想如下场景了, t1线程运行了, 执行到了”other.lock.notify()”, 然而 t2线程此时还没有被wait掉, 那么 此时是不是就构成了”死锁”, 在此场景下面, t1, t2两个线程都会wait掉, 而不会有其他的线程唤醒他们, 因此 程序就这样僵持下去了, 直到XXX
2. 另外的一个死锁的原因来了, 当前线程唤醒了另外的一个线程”other.lock.notify()”, 而执行到另外线程的notify的时候”other.lock.notify()”, 当前线程还没有走到wait这一步”lock.wait();”, 造成了死锁
难道说上面的思路存在问题嘛?? no 原因不在于此, 原因在于 实现的家伙太菜了 哈哈哈 就是我嘛
然后 之后的时候, 通过查阅资料[refer : http://jeasonjack.iteye.com/blog/1844512], 我看到了另外的一个版本的实现, 当然 思路和上面的思路是一样的, 存在一些不同的地方
Code02
// 两条线程, 打印出121212 public static void main(String[] args) { MyThread03 t01 = new MyThread03(1), t02 = new MyThread03(2); t01.start(); t02.start(); } // MyThread static class MyThread03 extends Thread { static Object lock = new Object(); private int output; // 初始化 public MyThread03(int output) { this.output = output; } // run @Override public void run() { // 可能存在第二个线程还没有wait, 结果 第一个线程notify了lock上面等待的线程[为空], 从而 导致死锁 // 一个不推荐, 但是 又想不到其他的好方法了, Thread.sleep() 控制流程, 以后 再回来想吧 if(output == 1) { Tools.sleep(1 * 1000); } if(output == 2) { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } while(true) { synchronized (lock) { System.out.println(output); lock.notify(); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
这样, 程序就”正常”了
对比一下 上面的存在的两个问题, 第一个问题, 被”Tools.sleep(1 * 1000);”, “解决”掉了, 第二个问题, 因为使用的是用一个对象的锁, 而且 未申请此对象的锁等待的线程仅此一个, 因此 不存在上面的第二个问题
不过 这里要说明的是, 使用”Thread.sleep(long millis) “来控制程序的流程, 不提倡使用, 请慎用
我记得tij中有两个编写java程序的原则, 一个是永远不要通过线程的优先级来控制程序的流程, 还有一个是什么忘记了 [刚才去翻了一下当时做的记录, 也没有找到, 管它的呢, 先记录在这里吧, 以后 找到了再填充回来]
然后, 在分享一个使用一个标志变量 + 忙等, 来实现的方法
refer : http://bbs.csdn.net/topics/320132441
Code03
// 两条线程, 打印出121212 public static void main(String[] args) { MyThread02 t01 = new MyThread02(1), t02 = new MyThread02(2); t01.start(); t02.start(); } // MyThread static class MyThread02 extends Thread { static volatile boolean isPrint1 = true; private int output; // 初始化 public MyThread02(int output) { this.output = output; } // run @Override public void run() { while(true) { if(isPrint1) { if(output == 1) { System.out.println(output); isPrint1 = ! isPrint1; } } else { if(output == 2) { System.out.println(output); isPrint1 = ! isPrint1; } } } } }
看到了吧, 实现也是非常的简洁呢, 使用isPrint1为volitile, 来保证了其他线程的可见性, 当isPrint1为true的时候, 线程1执行打印业务, 线程2什么都不干, 继续进入下一个循环, 当isPring为false的时候, 线程1什么都不干, 进入下一个循环, 线程2执行打印业务
相对的来说, 这个效率应该是比较高的吧, 毕竟业务太简单了
总结
啊 吃饭了, 写了一个小时, 好累啊
参考
线程交替执行?? –2016.08.09
http://bbs.csdn.net/topics/320132441
http://jeasonjack.iteye.com/blog/1844512
注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!
- 08 两个线程交替打印121212...
- 两个线程交替打印ABABAB
- 两个线程交替打印ABABAB
- 两个线程交替打印ABCDEF
- 两个线程的交替打印
- 两个线程交替打印字母 java
- Java实现两个线程交替打印问题
- wait,notify实现两个线程交替打印
- linux两个线程交替打印数字
- 两个线程每隔一秒钟交替打印5个数
- Java两个线程交替打印(实现Runnable接口)
- 面试题一:实现两个线程交替打印数字
- 多线程技术: 两个线程交替打印奇数和偶数
- 线程交替打印
- 两个线程交替执行
- 两个线程交替执行
- 使用Java线程并发库实现两个线程交替打印的线程题
- 2个线程交替打印
- Java中this关键字的几种用法-------转载
- 面试题——栈与队列的应用(下)
- 广义表(非线性结构)
- 数据结构--二叉树
- mathematica的图像处理0--七夕特刊
- 08 两个线程交替打印121212...
- 线索化二叉树
- 面试题—宏、函数、宏函数、inline函数的区别与联系
- jQuery编写动态评分小星星的插件
- linux系统中‘find’的详细用法
- 数据结构—各类‘排序算法’实现(上)
- 数据结构—各类‘排序算法’实现(下)
- 数据存在?-‘布隆过滤器’
- C++‘异常’处理机制