收藏 分享(赏)

java并发编程--一道经典多线程题的2种解法.docx

上传人:scg750829 文档编号:8090956 上传时间:2019-06-08 格式:DOCX 页数:7 大小:29.88KB
下载 相关 举报
java并发编程--一道经典多线程题的2种解法.docx_第1页
第1页 / 共7页
java并发编程--一道经典多线程题的2种解法.docx_第2页
第2页 / 共7页
java并发编程--一道经典多线程题的2种解法.docx_第3页
第3页 / 共7页
java并发编程--一道经典多线程题的2种解法.docx_第4页
第4页 / 共7页
java并发编程--一道经典多线程题的2种解法.docx_第5页
第5页 / 共7页
点击查看更多>>
资源描述

1、问题的描述启动 3个线程打印递增的数字, 线程 1先打印 1,2,3,4,5, 然后是线程 2打印6,7,8,9,10, 然后是线程 3打印 11,12,13,14,15. 接着再由线程 1打印16,17,18,19,20以此类推, 直到打印到 75. 程序的输出结果应该为:线程 1: 1线程 1: 2线程 1: 3线程 1: 4 线程 1: 5线程 2: 6线程 2: 7线程 2: 8线程 2: 9线程 2: 10.线程 3: 71线程 3: 72线程 3: 73线程 3: 74线程 3: 75解法一: 采用原始的 synchronized, wait(), notify(), notify

2、All()等方式控制线程.Java代码 1. public class NumberPrintDemo 2. / n为即将打印的数字 3. private static int n = 1; 4. / state=1表示将由线程 1打印数字, state=2 表示将由线程 2打印数字, state=3 表示将由线程 3打印数字 5. private static int state = 1; 6. 7. public static void main(String args) 8. final NumberPrintDemo pn = new NumberPrintDemo(); 9. new

3、 Thread(new Runnable() 10. public void run() 11. / 3个线程打印 75个数字, 单个线程每次打印 5个连续数字, 因此每个线程只需执行 5次打印任务. 3*5*5=75 12. for (int i = 0; i 5; i+) 13. / 3个线程都使用 pn对象做锁, 以保证每个交替期间只有一个线程在打印 14. synchronized (pn) 15. / 如果 state!=1, 说明此时尚未轮到线程1打印, 线程 1将调用 pn的 wait()方法, 直到下次被唤醒 16. while (state != 1) 17. try 18.

4、 pn.wait(); 19. catch (InterruptedException e) 20. e.printStackTrace(); 21. 22. / 当 state=1时, 轮到线程 1打印 5次数字 23. for (int j = 0; j 5; j+) 24. / 打印一次后 n自增 25. System.out.println(Thread.currentThread().getName() 26. + “: “ + n+); 27. 28. System.out.println(); 29. / 线程 1打印完成后, 将 state赋值为 2,表示接下来将轮到线程 2打

5、印 30. state = 2; 31. / notifyAll()方法唤醒在 pn上 wait的线程 2和线程 3, 同时线程 1将退出同步代码块, 释放 pn锁. 32. / 因此 3个线程将再次竞争 pn锁 33. / 假如线程 1或线程 3竞争到资源, 由于state不为 1或 3, 线程 1或线程 3将很快再次 wait, 释放出刚到手的pn锁. 34. / 只有线程 2可以通过 state判定, 所以线程 2一定是执行下次打印任务的线程. 35. / 对于线程 2来说, 获得锁的道路也许是曲折的, 但前途一定是光明的. 36. pn.notifyAll(); 37. 38. 39.

6、 40. , “线程 1“).start(); 41. 42. new Thread(new Runnable() 43. public void run() 44. for (int i = 0; i 5; i+) 45. synchronized (pn) 46. while (state != 2) 47. try 48. pn.wait(); 49. catch (InterruptedException e) 50. e.printStackTrace(); 51. 52. for (int j = 0; j 5; j+) 53. System.out.println(Thread.

7、currentThread().getName() 54. + “: “ + n+); 55. 56. System.out.println(); 57. state = 3; 58. pn.notifyAll(); 59. 60. 61. 62. , “线程 2“).start(); 63. 64. new Thread(new Runnable() 65. public void run() 66. for (int i = 0; i 5; i+) 67. synchronized (pn) 68. while (state != 3) 69. try 70. pn.wait(); 71.

8、 catch (InterruptedException e) 72. e.printStackTrace(); 73. 74. for (int j = 0; j 5; j+) 75. System.out.println(Thread.currentThread().getName() 76. + “: “ + n+); 77. 78. System.out.println(); 79. state = 1; 80. pn.notifyAll(); 81. 82. 83. 84. , “线程 3“).start(); 85. 86. 解法二: 采用 JDK1.5并发包提供的 Lock, C

9、ondition等类的相关方法控制线程.Java代码 1. public class NumberPrint implements Runnable 2. private int state = 1; 3. private int n = 1; 4. / 使用 lock做锁 5. private ReentrantLock lock = new ReentrantLock(); 6. / 获得 lock锁的 3个分支条件 7. private Condition c1 = lock.newCondition(); 8. private Condition c2 = lock.newCondit

10、ion(); 9. private Condition c3 = lock.newCondition(); 10. 11. Override 12. public void run() 13. new Thread(new Runnable() 14. public void run() 15. for (int i = 0; i 5; i+) 16. try 17. / 线程 1获得 lock锁后, 其他线程将无法进入需要 lock锁的代码块. 18. / 在 lock.lock()和 lock.unlock()之间的代码相当于使用了 synchronized(lock) 19. lock.

11、lock(); 20. while (state != 1) 21. try 22. / 线程 1竞争到了 lock, 但是发现 state不为 1, 说明此时还未轮到线程 1打印. 23. / 因此线程 1将在 c1上 wait 24. / 与解法一不同的是, 三个线程并非在同一个对象上 wait, 也不由同一个对象唤醒 25. c1.await(); 26. catch (InterruptedException e) 27. e.printStackTrace(); 28. 29. / 如果线程 1竞争到了 lock, 也通过了state判定, 将执行打印任务 30. for (int

12、j = 0; j 5; j+) 31. System.out.println(Thread.currentThread().getName() 32. + “: “ + n+); 33. 34. System.out.println(); 35. / 打印完成后将 state赋值为 2, 表示下一次的打印任务将由线程 2执行 36. state = 2; 37. / 唤醒在 c2分支上 wait的线程 2 38. c2.signal(); 39. finally 40. / 打印任务执行完成后需要确保锁被释放,因此将释放锁的代码放在 finally中 41. lock.unlock(); 42

13、. 43. 44. 45. , “线程 1“).start(); 46. 47. new Thread(new Runnable() 48. public void run() 49. for (int i = 0; i 5; i+) 50. try 51. lock.lock(); 52. while (state != 2) 53. try 54. c2.await(); 55. catch (InterruptedException e) 56. e.printStackTrace(); 57. 58. for (int j = 0; j 5; j+) 59. System.out.pr

14、intln(Thread.currentThread().getName() 60. + “: “ + n+); 61. 62. System.out.println(); 63. state = 3; 64. c3.signal(); 65. finally 66. lock.unlock(); 67. 68. 69. 70. , “线程 2“).start(); 71. 72. new Thread(new Runnable() 73. public void run() 74. for (int i = 0; i 5; i+) 75. try 76. 77. lock.lock(); 7

15、8. while (state != 3) 79. try 80. c3.await(); 81. catch (InterruptedException e) 82. e.printStackTrace(); 83. 84. for (int j = 0; j 5; j+) 85. System.out.println(Thread.currentThread().getName() 86. + “: “ + n+); 87. 88. System.out.println(); 89. state = 1; 90. c1.signal(); 91. finally 92. lock.unlo

16、ck(); 93. 94. 95. 96. , “线程 3“).start(); 97. 98. 99. public static void main(String args) 100. new NumberPrint().run(); 101. 102. 总结: 对比解法一和解法二, 显然解法二是更好的解决方案. 解法一的问题在于无法进行精确唤醒, 比如线程 1执行完打印任务并调用 pn.notifyAll()方法后, 3 个线程将再次竞争锁, 而不是精确唤醒线程 2. 虽然线程 2最终将赢得锁, 下一次的打印任务也肯定会由线程 2执行, 但是竞争的持续时间是不可预知的, 只能看线程 2的人品. 最糟糕的情形可以是: 线程 3竞争到了锁, 紧接着 wait. 接下来线程 1也竞争到了锁, 然后线程 1也 wait. 此时就再也没有其他线程跟线程 2竞争了, 线程2终于艰难的赢得了锁.

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报