【问题标题】:Why does this threaded code hang为什么这个线程代码挂起
【发布时间】:2012-01-16 21:45:09
【问题描述】:

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

我不知道怎么会有问题。 flag 可以为真或假,因此只有producerconsumer 之一将进入if 语句。在其中一个进入if 后,它将使用对象r 进入监视器(两者都使用相同的对象引用进行初始化)。唯一可能发生的问题是increment_decrement () 函数调用正在修改r 对象,而get_flag () 同时读取标志,但即使那样它也不会在该迭代中进入if,但它会在下一次迭代时进入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)
     {
     }
   }
}

【问题讨论】:

  • 在一个完全不相关的注释中,你真的应该用大写的第一个字母来命名你的类:Producer、Consumer、Resource...
  • @OlivierCroisier:同意,(我一个朋友的代码,贴出原文)

标签: java synchronization synchronized


【解决方案1】:

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

【讨论】:

  • 但是为什么使get_flag ()同步工作?使其同步是否强制从内存中读取标志?
  • 是的。使它成为volatile也是如此。否则,该值可以在本地缓存,甚至可以放在寄存器中而不是从内存中读取。您可以在完全不同步的情况下编写此代码。 ;)
【解决方案2】:

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

【讨论】:

  • 但是为什么让get_flag ()同步工作?使其同步是否强制从内存中读取标志?
  • 它强制更新或访问在线程之间同步。使用volatile,这是通过内存屏障完成的,它确保其他线程的所有更新都在当前线程上读取值之前完成。 AtomicBoolean 还保证线程之间的更新是同步的。
【解决方案3】:

这个生产者/消费者的实现很奇怪。

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

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

【讨论】:

  • 是的,没错,但主要目标是了解程序为何停止。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多