黑马程序员技术交流社区

标题: 等待唤醒机制和CPU背后的故事,纯技术贴! [打印本页]

作者: 赵玮_Tom    时间: 2012-5-14 20:32
标题: 等待唤醒机制和CPU背后的故事,纯技术贴!
学完多线程技术,并了解了线程和CPU的运行原理。可以利用等待唤醒机制来控制线程得到或放弃CPU执行权。那么,不借助等待唤醒机制,我们是否也能实现对多线程的控制,达到相同效果呢?可能你会认为这是痴人说梦。但仔细看完下面的程序,希望能对多线程有更深的了解。
  1. /*
  2. 该例没有使用”等待唤醒“机制,却依然实现了多线程对同一资源进行操作的效果(当然效率比使用等待唤醒机制的时候要低)。
  3. */
  4. class Res
  5. {
  6. /*定义flag变量,用于标记生产者和消费者的
  7. 动作交替。如果flag为true,生产者可以进行
  8. ”生产“,消费者不能进行”消费“;反之,亦然。*/
  9. private boolean flag=true;

  10. /*定义mark变量,用于标记生产的内容。如果
  11. mark为true,生产”张三“,如果mark为false,
  12. 生产”rose“。*/
  13. boolean mark = true;

  14. /*定义count指针,用于给生产的信息编号*/
  15. private int count = 1;

  16. private String name;
  17. private String sex;


  18. //同步方法,用于生产者设置信息。
  19. public synchronized void setInfo(String name, String sex)
  20. {
  21. /*首先判断flag标记。注:在flag为false的情况下,即使消费者线程得到
  22. CPU执行权,也不会执行任何动作*/
  23. if(flag)
  24. {
  25. this.name=name+(count++);
  26. this.sex=sex;
  27. System.out.println(Thread.currentThread().getName()+"——生产了:"+this.name+"-----"+this.sex);
  28. flag=false;//改变flag标记
  29. mark=(mark==true)?false:true;//改变mark标记
  30. }
  31. }
  32. //同步方法,用于消费者获取信息
  33. public synchronized void getInfo()
  34. {
  35. /*首先判断flag标记。注:在flag为true的情况下,即使生产者线程得到
  36. CPU执行权,也不会执行任何动作*/
  37. if(!flag)
  38. {
  39. System.out.println(Thread.currentThread().getName()+"——消费了:"+this.name+"-----"+this.sex);
  40. flag=true;//改变flag标记
  41. }
  42. }
  43. }
  44. class Producer implements Runnable
  45. {
  46. private Res res;

  47. public Producer(Res res)
  48. {
  49. this.res=res;
  50. }
  51. public void run()
  52. {
  53. while(true)
  54. {
  55. if(res.mark)//mark为true,生产”张三“
  56. {
  57. res.setInfo("张三", "男");
  58. }
  59. else//mark为false,生产”rose“
  60. {
  61. res.setInfo("rose", "female");
  62. }
  63. }
  64. }
  65. }
  66. class Consumer implements Runnable
  67. {
  68. private Res res;
  69. public Consumer(Res res)
  70. {
  71. this.res=res;
  72. }
  73. public void run()
  74. {
  75. while(true)//消费者消费”信息“
  76. {
  77. res.getInfo();
  78. }
  79. }
  80. }
  81. public class ThreadDemo02
  82. {
  83. public static void main(String args [])
  84. {
  85. Res res = new Res();
  86. //创建两个生产者线程和两个消费者线程
  87. Producer p1 = new Producer(res);
  88. Producer p2 = new Producer(res);
  89. Consumer c1 = new Consumer(res);
  90. Consumer c2 = new Consumer(res);

  91. new Thread(p1).start();
  92. new Thread(p2).start();
  93. new Thread(c1).start();
  94. new Thread(c2).start();
  95. }
  96. }
复制代码
重点说明:
多线程对同一资源操作的问题中,有两点是至关重要的:
1)CPU工作原理:CPU是以极高的频率在多个线程之间做着快速的切换,并不是长时间只执行一个线程。
2)定义资源标记:这里说的“资源标记”就是boolean型变量,它的变化记录着该由哪些线程执行操作,哪些线程不该执行操作。
    该例中涉及到两个“资源标记”:flag和mark。flag用于记录该对资源进行生产操作还是消费操作的情况。mark用于记录该生产哪种类型的产品(“张三”或“rose ”)。
    只要定义好这两个“标记”,即使不借助等待唤醒机制,也可以实现多个生产者和多个消费者对同一资源进行操作的效果。

当然,这个程序的执行效率要低于加入等待唤醒机制的程序。因为正常程序中,线程遇到wait()会释放执行资格。该程序中却不存在释放执行资格的情况,而是借助CPU的快速切换实现效果。
该例目的在于使大家明白,实现多线程对同一资源进行操作时,并不是必须要利用等待唤醒机制,只是一般程序都要提高效率,故等待唤醒这种机制会使用地比较普遍。
附执行效果图。期待交流。

Thread.png (10.45 KB, 下载次数: 51)

Thread.png

作者: 索学超    时间: 2012-5-14 20:37
顶一个。。。。
作者: 崔陈喜    时间: 2012-5-14 21:58
顶起,顶起!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2