phoxis
phoxis

Reputation: 61910

Why does this threaded code hang

In the below code, when I execute the producercon class, sometimes the execution stucks, looks like a deadlock. But if i make the get_flag () synchronized then there are no such problems.

I cannot figure out how there can be a problem. the flag can either true or false so only one of the producer or consumer will get into the if statement. After one of them enters the if it will enter the monitor with object r (both are initialized with the same object reference). The only problem which can happen that the r object being modified by the increment_decrement () function call, and the get_flag () reading the flag at the same time, but even then it will not enter the if in that iteration, but it will enter the if block on the next iteration, and even if the first thread did not leave the monitor, it will wait there for it (before the synchronized block).

How, and why is the program halting/hanging if get_flag () is not made 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)
     {
     }
   }
}

Upvotes: 4

Views: 146

Answers (3)

Olivier Croisier
Olivier Croisier

Reputation: 6149

This producer/consumer implementation is quite weird.

Neither the producer not the consumer wait for the resource to be in the adequate state, and the resource access is not well protected (the flag should be guarded by some lock to ensure its visibility between threads).

One way to improve on this design would be to use the standart wait/notify system. Another way would be to use a Semaphore in the Resource to ensure only one thread can access the resource at one given time. Finally, you could use a higher-level construct such an java.util.concurrent.SynchronousQueue to pass some data directly from the producer to the consumer.

Upvotes: 0

Gray
Gray

Reputation: 116878

You need to make your boolean either volatile or an AtomicBoolean. Right now multiple threads are trying to access the boolean that is in no way synchronized.

Upvotes: 4

Peter Lawrey
Peter Lawrey

Reputation: 533492

Your call to get_flag() is not thread safe nor volatile. This means in the cache of thread 1 it can be true while in the cache of thread 2 it can be false.

Upvotes: 6

Related Questions