黑马程序员技术交流社区

标题: 线程问题 [打印本页]

作者: treecolor166    时间: 2013-12-28 13:48
标题: 线程问题
本帖最后由 treecolor166 于 2013-12-29 23:55 编辑

请问下面的代码为什么只有2个线程在打印其它线程怎么都停在那里不输出了呢
public class ProducerConsumerDemo2
{
public static void main(String[] args)
{
  Resource r=new Resource();

  Producer pro=new Producer(r);
  Consumer con=new Consumer(r);

  Thread t1=new Thread(pro);
  Thread t2=new Thread(pro);
  Thread t3=new Thread(con);
  Thread t4=new Thread(con);

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

class Resource
{
private String name;
private int count=1;
private boolean flag;

//创建锁
Lock lock=new ReentrantLock();

//通过锁对象创建2组监视器对象,分别用于监视生产者和消费者
Condition producer_con=lock.newCondition();
Condition consumer_con=lock.newCondition();

public synchronized void set(String name)
{
  lock.lock();
  try
  {
   while(flag)
    try{producer_con.await();}catch(InterruptedException e){}

   this.name=name+(count++);
   System.out.println(Thread.currentThread().getName()+"....生产"+this.name);
   flag=true;

   consumer_con.signal();
  }
  finally
  {
   lock.unlock();
  }
}

public synchronized void out()
{
  lock.lock();
  try
  {
   while(!flag)
    try{consumer_con.await();}catch(InterruptedException e){}
   
   System.out.println(Thread.currentThread().getName()+"*************消费"+this.name);
   flag=false;
   producer_con.signal();
  }
  finally
  {
   lock.unlock();
  }
}
}

class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
  this.r=r;
}

public void run()
{
  while(true)
  {
   r.set("商品");
  }
}
}

class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
  this.r=r;
}

public void run()
{
  while(true)
  {
   r.out();
  }
}
}



作者: 胡永城    时间: 2013-12-28 20:00
本帖最后由 胡永城 于 2013-12-28 20:01 编辑

真心纠结的问题啊,不过找到问题了:

Resource类中,public synchronized void set(String name) 方法中:
producer_con.await();//这一句。

当线程Thread-0执行到这一句时,此线程拿着此方法的锁this,处于等待状态。
(API文档:
void await()
           throws InterruptedException造成当前线程在接到信号或被中断之前一直处于等待状态。)

此时如果Thread-1执行到public synchronized void set(String name) 方法。
this锁被Thread-0拿着,没有线程执行consumer_con.signal();语句。Thread-0冻结状态,Thread-1进不来方法。。。

同样的Thread-2、Thread-3也发生这种情况,造成死锁,所以程序就卡在这里了。

以下是测试代码:

  1. import java.util.concurrent.locks.Condition;
  2. import java.util.concurrent.locks.Lock;
  3. import java.util.concurrent.locks.ReentrantLock;

  4. //请问下面的代码为什么只有2个线程在打印其它线程怎么都停在那里不输出了呢
  5. public class ProducerConsumerDemo2 {
  6.         public static void main(String[] args) {
  7.                 Resource r = new Resource();

  8.                 Producer pro = new Producer(r);
  9.                 Consumer con = new Consumer(r);

  10.                 //只测试t1、t2构成的死锁。也可以同时测t3、t4.
  11.                 Thread t1 = new Thread(pro);
  12.                 Thread t2 = new Thread(pro);
  13.                 //Thread t3 = new Thread(con);
  14.                 //Thread t4 = new Thread(con);

  15.                 t1.start();
  16.                 t2.start();
  17.                 //t3.start();
  18.         //        t4.start();
  19.         }
  20. }

  21. class Resource {
  22.         static int p=0;//此静态变量用于监视执行顺序。
  23.         private String name;
  24.         private int count = 1;
  25.         private boolean flag;

  26.         // 创建锁
  27.         Lock lock = new ReentrantLock();

  28.         // 通过锁对象创建2组监视器对象,分别用于监视生产者和消费者
  29.         Condition producer_con = lock.newCondition();
  30.         Condition consumer_con = lock.newCondition();

  31.         public synchronized void set(String name) {
  32.                 lock.lock();
  33.                 System.out.println(Thread.currentThread().getName() +"---set-上--"+Resource.p+++"---"+flag);//监视
  34.                 try {
  35.                         while (flag)
  36.                                 try {
  37.                                         System.out.println(Thread.currentThread().getName() +"---set---"+Resource.p+++"---"+flag);//监视
  38.                                         producer_con.await();
  39.                                         System.out.println(Thread.currentThread().getName() +"---set-await--"+Resource.p+++"---"+flag);//监视
  40.                                 } catch (InterruptedException e) {
  41.                                 }

  42.                         this.name = name + (count++);
  43.                         System.out.println(Thread.currentThread().getName() + "....生产"
  44.                                         + this.name);
  45.                         flag = true;
  46.                         System.out.println(Thread.currentThread().getName() +"---set-下--"+Resource.p+++"---"+flag);//监视
  47.                         consumer_con.signal();
  48.                 } finally {
  49.                         lock.unlock();
  50.                 }
  51.         }

  52.         public synchronized void out() {
  53.                 //System.out.println(Thread.currentThread().getName() +"---out()-上--"+Resource.p+++"---"+flag);
  54.                 lock.lock();
  55.                 try {
  56.                         while (!flag)
  57.                                 try {
  58.                                         consumer_con.await();
  59.                                 } catch (InterruptedException e) {
  60.                                 }

  61.                         System.out.println(Thread.currentThread().getName()
  62.                                         + "*************消费" + this.name);
  63.                         flag = false;
  64.                         //System.out.println(Thread.currentThread().getName() +"---out()-下--"+Resource.p+++"---"+flag);
  65.                         producer_con.signal();
  66.                 } finally {
  67.                         lock.unlock();
  68.                 }
  69.         }
  70. }

  71. class Producer implements Runnable {
  72.         private Resource r;

  73.         Producer(Resource r) {
  74.                 this.r = r;
  75.         }

  76.         public void run() {
  77.                 while (true) {
  78.                         System.out.println(Thread.currentThread().getName() +"--Producer-run()---"+Resource.p+++"---");//监视
  79.                         r.set("商品");
  80.                 }
  81.         }
  82. }

  83. class Consumer implements Runnable {
  84.         private Resource r;

  85.         Consumer(Resource r) {
  86.                 this.r = r;
  87.         }

  88.         public void run() {
  89.                 while (true) {
  90.                         //System.out.println(Thread.currentThread().getName() +"--Consumer-run()---"+Resource.p+++"---");
  91.                         r.out();
  92.                 }
  93.         }
  94. }
复制代码

我只发现了这个情况,如果有其他的情况和我说说啊。


作者: treecolor166    时间: 2013-12-29 00:35
多谢你的提醒,把synchronized去掉之后就正常了
作者: 胡永城    时间: 2013-12-29 03:04
treecolor166 发表于 2013-12-29 00:35
多谢你的提醒,把synchronized去掉之后就正常了

我第一次回答有一点错误:

producer_con.await();//这一句。
当线程Thread-0执行到这一句时,此线程拿着此方法的锁this,处于等待状态。

这两句,我当时理解为没有释放锁,其实释放锁了。希望对你不要产生错误的引导。

await方法:与此 Condition 相关的锁以原子方式释放,并且出于线程调度的目的,将禁用当前线程。

同步方法的锁是this,就是此方法的调用者。执行await后, Condition 相关的锁被释放,this锁却没有释放。




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