[转帖]经典多线程实例:生产者消费者问题_Android, Python及开发编程讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Android, Python及开发编程讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 4432 | 回复: 0   主题: [转帖]经典多线程实例:生产者消费者问题        下一篇 
zhou
注册用户
等级:中校
经验:2210
发帖:125
精华:6
注册:2012-11-19
状态:离线
发送短消息息给zhou 加好友    发送短消息息给zhou 发消息
发表于: IP:您无权察看 2012-11-23 14:57:01 | [全部帖] [楼主帖] 楼主

大部分人在理解Java的多线程这个问题有点困难,尤其是一些刚开始接触的编程语言是C语言的人。考虑到用C语言的人接触的都是一个主线程,下面给出的例子并没有太复杂的结构。主要是用来理解多线程的机制。

采用的例子:生产者消费者问题。

SyncStack存储WoTou

Producer生产WoTou

Consumer消费WoTou

[java] view plaincopyprint?
01.package com.example.thread;
02.
03.public class ProducerConsumer {
      04.
      05. public static void main(String[] args) {
            06. SyncStack ss = new SyncStack();
            07. Producer p = new Producer(ss);
            08. Consumer c = new Consumer(ss);
            09.
            10. new Thread(p).start();
            11. new Thread(c).start();
      12. }
      13.
14.}
15.
16.
17.class WoTou {
      18. int id;
      19.
      20. public WoTou(int id) {
            21. super();
            22. this.id = id;
      23. }
      24.
      25. @Override
      26. public String toString() {
            27. return "WoTou [id=" + id + "]";
      28. }
      29.
30.}
31.
32.
33.class SyncStack {
      34. int index = 0;
      35.
      36. WoTou[] arrWT = new WoTou[6];
      37.
      38. public synchronized void push(WoTou wt) {
            39. while(index == arrWT.length) {
                  40. try {
                        41. this.wait();
                  42. } catch (InterruptedException e) {
                        43. e.printStackTrace();
                  44. }
            45. }
            46. this.notify();
            47. arrWT[index] = wt;
            48. index++;
      49. }
      50.
      51. public synchronized WoTou pop() {
            52. while(index == 0) {
                  53. try {
                        54. this.wait();
                  55. } catch (InterruptedException e) {
                        56. e.printStackTrace();
                  57. }
            58. }
            59. this.notify();
            60. index--;
            61. return arrWT[index];
      62. }
63.}
64.
65.
66.class Producer implements Runnable {
      67. SyncStack ss = null;
      68.
      69. public Producer(SyncStack ss) {
            70. super();
            71. this.ss = ss;
      72. }
      73.
      74. @Override
      75. public void run() {
            76. for(int i=0; i<20; i++) {
                  77. WoTou wt = new WoTou(i);
                  78. ss.push(wt);
                  79. System.out.println("生产:" + wt);
            80. }
            81.
      82. }
      83.
84.}
85.
86.class Consumer implements Runnable {
      87. SyncStack ss = null;
      88.
      89. public Consumer(SyncStack ss) {
            90. super();
            91. this.ss = ss;
      92. }
      93.
      94. @Override
      95. public void run() {
            96. for(int i=0; i<20; i++) {
                  97. WoTou wt = ss.pop();
                  98. System.out.println("消费:" + wt);
            99. }
      100. }
      101.
102.}
103.
104./*


105. wait(),notify(),notifyAll()方法来自java.lang.Object

106.
107.wait()
108.public final void wait()


109.                throws InterruptedException在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执�� wait(0) 调用一样。 
110.当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。 

111.


112.对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用: 

113.
114.synchronized (obj) {
      115.while (<condition does not hold>)
      116.obj.wait();
      117.... // Perform action appropriate to condition
118. }


119. 此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。 

120.


121.抛出: 
122.IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。 
123.InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。
124.另请参见:

125.notify(), notifyAll()
126.
127.
128.
129.
130.
131.notify
132.public final void notify()


133.唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。 
134.直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。 

135.


136.此方法只应由作为此对象监视器的所有者的线程来��用。通过以下三种方法之一,线程可以成为此对象监视器的所有者: 

137.


138.通过执行此对象的同步实例方法。 
139.通过执行在此对象上进行同步的 synchronized 语句的正文。 
140.对于 Class 类型的对象,可以通过执行该类的同步静态方法。 
141.一次只能有一个线程拥有对象的监视器。 

142.
143.


144.抛出: 
145.IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
146.另请参见:

147.notifyAll(), wait()
148.
149.
150.
151.
152.
153.notifyAll


154.public final void notifyAll()唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个 wait 方法,在对象的监视器上等待。 
155.直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。 

156.


157.此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。 

158.
159.


160.抛出: 
161.IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
162.另请参见:

163.notify(), wait()
164.*/
package com.example.thread;
public class ProducerConsumer {
      public static void main(String[] args) {
            SyncStack ss = new SyncStack();
            Producer p = new Producer(ss);
            Consumer c = new Consumer(ss);
            new Thread(p).start();
            new Thread(c).start();
      }
}
class WoTou {
int id;
public WoTou(int id) {
      super();
      this.id = id;
}
@Override
public String toString() {
      return "WoTou [id=" + id + "]";
}
}
class SyncStack {
int index = 0;
WoTou[] arrWT = new WoTou[6];
public synchronized void push(WoTou wt) {
      while(index == arrWT.length) {
            try {
                  this.wait();
            } catch (InterruptedException e) {
                  e.printStackTrace();
            }
      }
      this.notify();
      arrWT[index] = wt;
      index++;
}
public synchronized WoTou pop() {
      while(index == 0) {
            try {
                  this.wait();
            } catch (InterruptedException e) {
                  e.printStackTrace();
            }
      }
      this.notify();
      index--;
      return arrWT[index];
}
}
class Producer implements Runnable {
      SyncStack ss = null;
      public Producer(SyncStack ss) {
            super();
            this.ss = ss;
      }
      @Override
      public void run() {
            for(int i=0; i<20; i++) {
                  WoTou wt = new WoTou(i);
                  ss.push(wt);
                  System.out.println("生产:" + wt);
            }
      }
}
class Consumer implements Runnable {
      SyncStack ss = null;
      public Consumer(SyncStack ss) {
            super();
            this.ss = ss;
      }
      @Override
      public void run() {
            for(int i=0; i<20; i++) {
                  WoTou wt = ss.pop();
                  System.out.println("消费:" + wt);
            }
      }
}
/*


 wait(),notify(),notifyAll()方法来自java.lang.Object

wait()
public final void wait()


                throws InterruptedException在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。
当前线程必须拥有此对象监视器。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。

对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:

synchronized (obj) {
      while (<condition does not hold>)
      obj.wait();
      ... // Perform action appropriate to condition
}


 此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。

抛出:
IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
InterruptedException - 如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的中断状态 被清除。
另请参见:

notify(), notifyAll()
notify
public final void notify()


唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。
直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。

此方法只应由作为此对象监视器的所有者的线程来调用。通过以下三种方法之一,线程可以成为此对象监视器的所有者:

通过执行此对象的同步实例方法。
通过执行在此对象上进行同步的 synchronized 语句的正文。
对于 Class 类型的对象,可以通过执行该类的同步静态方法。
一次只能有一个线程拥有对象的监视器。

抛出:
IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
另请参见:

notifyAll(), wait()
notifyAll


public final void notifyAll()唤醒在此对象监视器上等待的所有线程。线程通过调用其中一个 wait 方法,在对象的监视器上等待。
直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。

此方法只应由作为此对象监视器的所有者的线程来调用。有关线程能够成为监视器所有者的方法的描述,请参阅 notify 方法。

抛出:
IllegalMonitorStateException - 如果当前线程不是此对象监视器的所有者。
另请参见:

notify(), wait()
*/


运行结果我这不给出,大家可以运行下。加深一下理解。

注:while(index == 0),while(index == arrWT.length)两条语句不可以用if(index == 0),if(index == arrWT.length)
原因是如果在wait方法被打断的时候,不再检查临界值,用while循环可以一直很好的控制边界问题。

在编程以及写项目的时候特别需要注意这两个关键字的区别。

由于本人的水平有限,很多问题并没有给出太多的解释,如果你有任何疑问,希望你可以留言告诉我。

该贴被zhou编辑于2012-11-23 15:00:46



赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论