为什么这个线程代码会挂起

时间:2011-12-09 16:03:29

标签: java synchronization synchronized

在下面的代码中,当我执行producercon类时,有时执行卡住,看起来像死锁。但是,如果我使get_flag ()同步,那么就没有这样的问题了。

我无法弄清楚怎么会有问题。 flag可以是true或false,因此只有producerconsumer中的一个会进入if语句。在其中一个进入if之后,它将进入具有对象r的监视器(两者都使用相同的对象引用进行初始化)。 r函数调用increment_decrement ()对象被修改的唯一问题,get_flag ()同时读取标志,但即使这样,它也不会进入if在那次迭代中{1}},但它会在下一次迭代时进入if块,即使第一个线程没有离开监视器,它也会在那里等待它(在synchronized之前块)。

如果get_flag ()未成为synchronized,程序如何暂停/挂起?

import java.io.*;

class resource
{
   private boolean res, flag;

   resource ()
   {
     flag=false;
   }

   boolean get_flag ()
   {
     return flag;
   }

   void increment_decrement (String s,boolean t)
   {
     res=t;
     flag=t;
      try 
      {
        System.out.print("\n"+s+":"+res);
        Thread.sleep(200);
      }
      catch(InterruptedException e)
      {
      }
   }
}

class producer implements Runnable
{
    resource r1;
    Thread t1;

    producer(resource r)
    {
      r1 = r;
      t1 = new Thread(this);
      t1.start();
    }

    public void run ()
    {  
      while (true)
      {
        if(r1.get_flag () == false)
        {
          synchronized(r1)
          {
            r1.increment_decrement("Producer",true);
          }
        }
      }
    }

   public void waitForThread () throws InterruptedException
   {
     t1.join ();
   }
}

class consumer implements Runnable
{
   resource r2;
   Thread t2;

   consumer(resource r)
   {
     r2 = r;
     t2 = new Thread (this);
     t2.start();
   }

   public void run()
   {
     while (true)
     {
       if(r2.get_flag () == true)
       {
         synchronized(r2)
         {
           r2.increment_decrement("Consumer",false);
         }
       }
     }
   }

   public void waitForThread () throws InterruptedException
   {
     t2.join ();
   }
} 

public class producercon
{
   public static void main(String args[])
   {
     try
     {
        System.out.print("PRESS CTRL+C TO TERMINATE\n");

        resource r = new resource();
        consumer c = new consumer(r);
        producer p = new producer(r);

        c.waitForThread ();
        p.waitForThread ();
     }
     catch(InterruptedException e)
     {
     }
   }
}

3 个答案:

答案 0 :(得分:6)

你对get_flag()的调用不是线程安全的,也不是volatile。这意味着在线程1的高速缓存中,它可以是真的,而在线程2的高速缓存中它可以是假的。

答案 1 :(得分:4)

您需要将布尔值设为volatileAtomicBoolean。现在,多个线程正在尝试访问无法同步的布尔值。

答案 2 :(得分:0)

这种生产者/消费者实施非常奇怪。

生产者和消费者都没有等待资源处于适当的状态,并且资源访问没有得到很好的保护(标志应该被一些锁保护以确保它在线程之间的可见性。)

改进此设计的一种方法是使用标准等待/通知系统。另一种方法是在资源中使用信号量,以确保在一个给定时间只有一个线程可以访问资源。最后,您可以使用更高级别的构造,例如java.util.concurrent.SynchronousQueue,将一些数据直接从生产者传递给使用者。