Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)
     {
     }
   }
}
like image 897
phoxis Avatar asked Dec 27 '22 09:12

phoxis


2 Answers

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.

like image 148
Peter Lawrey Avatar answered Jan 08 '23 08:01

Peter Lawrey


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.

like image 27
Gray Avatar answered Jan 08 '23 07:01

Gray