A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 庄星睿 中级黑马   /  2012-6-22 20:54  /  1982 人查看  /  7 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 庄星睿 于 2012-6-23 11:43 编辑

多个生产者这块视频看了几遍了,有几个问题越想越糊涂,我是这样实现的:
  1. class Resource
  2. {
  3. private String name;
  4. private int count=1;
  5. private boolean flag=false;
  6. //t1 t2
  7. public synchronized void set(String name)
  8. {
  9. if (this.flag)
  10. try{wait();}catch(InterruptedException e){} //t1等待状态 t2等待状态
  11. this.name=name+"....."+count++;
  12. System.out.println(Thread.currentThread().getName()+"....生产:--"+this.name);
  13. this.flag=true;
  14. notify();
  15. }

  16. //t3 t4
  17. public synchronized void out()
  18. {
  19. if (!this.flag)
  20. try{wait();}catch(InterruptedException e){} //t3等待 t4等待
  21. System.out.println(Thread.currentThread().getName()+"...消费:=========="+this.name);
  22. this.flag=false;
  23. notify();
  24. }
  25. }

  26. class Producer implements Runnable
  27. {
  28. private Resource res;
  29. Producer(Resource res)
  30. {
  31. this.res=res;
  32. }
  33. public void run()
  34. {
  35. while(true)
  36. {
  37. res.set("商品");
  38. }
  39. }

  40. }

  41. class Consumer implements Runnable
  42. {
  43. private Resource res;
  44. Consumer(Resource res)
  45. {
  46. this.res=res;
  47. }
  48. public void run()
  49. {
  50. while(true)
  51. {
  52. res.out();
  53. }
  54. }

  55. }



  56. class ProducerConsumerDemo
  57. {
  58. public static void main(String[] args)
  59. {
  60. Resource r=new Resource();

  61. /*
  62.    //这是视频里用
  63. Producer per=new Producer(r);
  64. Consumer con=new Consumer(r);

  65. Thread t1=new Thread(per);
  66. Thread t2=new Thread(per); //生产者2

  67. Thread t3=new Thread(con);
  68. Thread t4=new Thread(con); //消费者2
  69. */
  70. // 我是这样写的,也能实现视频里的哪些状态,但和上面的区别搞不清楚
  71. Producer per=new Producer(r);
  72. Producer per2=new Producer(r); //这样增加一个生产者对象
  73. Consumer con=new Consumer(r);
  74. Consumer con2=new Consumer(r); //这样增加一个消费者对象


  75. Thread t1=new Thread(per);
  76. Thread t2=new Thread(per2); //增加一个生产者线程

  77. Thread t3=new Thread(con);
  78. Thread t4=new Thread(con2); //增加一个消费者线程


  79. t1.start();
  80. t2.start();
  81. t3.start();
  82. t4.start();
  83. }
  84. }
复制代码
视频里创建多个生产者、消费者这样写的
Thread t1=new Thread(per);
Thread t2=new Thread(per); //生产者2
Thread t3=new Thread(con);
Thread t4=new Thread(con); //消费者2
那个生产者和消费者不是两个独立的对象吗,要增加生产者,消费者,得先创建生产者、消费者对象:
Producer per=new Producer(r);
Producer per2=new Producer(r); //这样增加一个生产者对象
Consumer con=new Consumer(r);
Consumer con2=new Consumer(r); //这样增加一个消费者对象

Thread t1=new Thread(per);
Thread t2=new Thread(per2); //增加一个生产者线程

Thread t3=new Thread(con);
Thread t4=new Thread(con2); //增加一个消费者线程
问题一:
这样写,我能实现和视频里的一样的状态,增加了生产者、消费者增加了相应的线程,但和视频里直接Thread有什么区别,感觉直接Thread好像将原来的复制了

问题二:
我的理解上就是 Input  Ouput 情况,先存入、后取出,加了同步防止同时操作Resource出现数据错乱,就好比有一个房间,有两个门(存和取),一个人从一个门往房间里存东西,另一个人从房间另一扇门取东西,加了同一把锁,同一时间段完成只能存入或只能取出动作,避免数据错乱,加了flag判断标记,让存入和取出交替进行,防止某个时间段重复执行存入或取出操作,现在又增加了一个生产者和消费者,就相当于又增加了一个input ouput,两个人存取操作,这时t1 ,t2,t3,t4,都持有相同的锁,相当于还是同时在一个房间里存取啊,那么既然t1线程拿了锁进去执行 wait()了,这时t2应该进不去啊,因为t1还没出来(按照那个火车上厕所的例子理解),t3进去从取的那个门取出数据,如果t3拿锁挂了,没出来,t4应该也进不去啊,他得等t3出来改了旗标才能进去 啊  ,就是说一个时间段内只能一个人在存或取
他这里是用同步函数实现的,怎里理解那个同步函数什么时候才算拿锁了就相当于 synchronized(obj){}是进代码块里拿锁,出代码块释放锁,那个同步函数呢,什么时候算拿,什么时候算释放  ?

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

7 个回复

倒序浏览
30.private Resource res;

31.Producer(Resource res)

32.{

33.this.res=res;

34.}

问题一:不管是生产者,还是消费者,他们都会是把相同的resource对象传递,操作的是同一个资源,所以你用同一个生产者开启两个个线程(老毕的写法);或者是创建两个生产者(你的写法),开启个自的线程,都是一样的作用。
68.Resource r=new Resource();
问题二:搞清楚第一个问题,自然迎刃而解,main中只创建了一个Resource对象,两个生产者线程都只能从set方法进,两个消费者线程都是从out方法出。

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
黄连兵 发表于 2012-6-22 21:27
30.private Resource res;

31.Producer(Resource res)

哥们,同一个生产者开启两个线程,是相当于一个人原来生产一个,现在同时生产两个,他不是还是相当于把他自己本身复制了吗?
还有第二个他进和出都要通过set和out方法,但一旦t1在wait()了,他现在释放锁了吗,如果没释放,t2不可能进得去啊,synchronized 他的锁是隐式的,他是在什么时候释放的啊,将同步代码块时,是出了代码块才把旗标该成0, 那个同步函数wait()那了,应该还没释放锁,这样即使t2有了cpu执行权,也进不了锁判断flag啊,我举得那个例子我自己都晕了
回复 使用道具 举报
本帖最后由 王明明 于 2012-6-22 23:05 编辑

class Resource
{
private String name;
private int count=1;
private boolean flag=false;
//t1 t2
public synchronized void set(String name)
{
if (this.flag)
try{wait();}catch(InterruptedException e){} //t1等待状态 t2等待状态
this.name=name+"....."+count++;
System.out.println(Thread.currentThread().getName()+"....生产:--"+this.name);
this.flag=true;
notify();
}
//t3 t4
public synchronized void out()
{
if (!this.flag)
try{wait();}catch(InterruptedException e){} //t3等待 t4等待
System.out.println(Thread.currentThread().getName()+"...消费:=========="+this.name);
this.flag=false;
notify();
}
}
class Producer implements Runnable
{
private Resource res;
Producer(Resource res)
{
this.res=res;
}
public void run()
{
while(true)
{
res.set("商品");
}
}
}
class Consumer implements Runnable
{
private Resource res;
Consumer(Resource res)
{
this.res=res;
}
public void run()
{
while(true)
{
res.out();
}
}
}

class ProducerConsumerDemo
{
public static void main(String[] args)
{
Resource r=new Resource();
/*
   //这是视频里用
Producer per=new Producer(r);
Consumer con=new Consumer(r);
Thread t1=new Thread(per);
Thread t2=new Thread(per); //生产者2  视频这是在一个厂子里面增加生产线 还是同一个厂子生产的
Thread t3=new Thread(con);
Thread t4=new Thread(con); //消费者2
*/
// 我是这样写的,也能实现视频里的哪些状态,但和上面的区别搞不清楚
Producer per=new Producer(r);
Producer per2=new Producer(r); //这样增加一个生产者对象  //你这里等于增加了一个工厂 本来是一个厂子商品 现在是两个 或者有可能2个厂子生产的东西都不一样 2个对象
Consumer con=new Consumer(r);
Consumer con2=new Consumer(r); //这样增加一个消费者对象

Thread t1=new Thread(per);
Thread t2=new Thread(per2); //增加一个生产者线程 //这里你是给一个新的厂子增加了新的生产线 概念完全不同了
Thread t3=new Thread(con);
Thread t4=new Thread(con2); //增加一个消费者线程

t1.start();
t2.start();
t3.start();
t4.start();
}
}

评分

参与人数 1技术分 +1 收起 理由
职业规划-刘倩老师 + 1 赞一个!

查看全部评分

回复 使用道具 举报
王明明 发表于 2012-6-22 23:03
class Resource
{
private String name;

嗯,那个之前银行储户的例子怎么理解,2个储户,每个储户存300,分三次
这个储户是怎么理解的,要是两个储户,两个存钱的人 Cus c1=new Cus(b) ;Cus c2=new Cus(b);两个人存钱嘛,当然得new Cus(b)两个对象
视频里是这样写的,相当于一个人开启两个存钱的线程,怎么理解
bank b=new bank();
Cus c=new Cus(b);
Thread t1=new Thread(c);
Thread t2=new Thread(c);
t1.start();
t2.srart();
第二个问题能帮我分析一下吗,我自己都晕了
回复 使用道具 举报
关于银行的那个例子,可以解释一下。
题目的意思是2个储户往银行的一个金库里存钱,这一个金库就是多线程所共享的数据。
金库——Bank,功能是将存进的钱往里加;
储户的行为——Cus,功能是分三次,存300
2个储户——创建的两个线程,同步往金库里存钱;


银行和消费者的例子,你都有一个概念模糊不清,就是,认为只要增加了一个生产者(消费者、储户),就是增加了一个对象,实际上增加的这个只是多了一个线程,而非对象。程序中取名Producer、Customer、Cus并不是所谓的生产者、消费者、储户,真正的意义是他们各自对于同一个共享数据的行为,这些行为不需要重复去建立对象,而是具备这些行为的人(线程)去实现。

可以仔细品味楼上标红字的部分,很清楚的解释。

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
庄星睿 发表于 2012-6-22 23:22
嗯,那个之前银行储户的例子怎么理解,2个储户,每个储户存300,分三次
这个储户是怎么理解的,要是两个 ...

bank b=new bank();
Cus c=new Cus(b);
Thread t1=new Thread(c);//你看这里 传入的是C 对象 其实2个 都是为C 对象开启的窗口Thread t2=new Thread(c);
t1.start();
t2.srart();

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
王明明 发表于 2012-6-23 09:50
bank b=new bank();
Cus c=new Cus(b);
Thread t1=new Thread(c);//你看这里 传入的是C 对象 其实2个 都 ...

OK了,谢谢
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马