title: Lock Not Being Released by Thread at the End of Run Method [Solved]
body: <p>So I'm trying to run a cafe simulation using Java's ReentrantLock and volatile. Basically I have a time thread that supposed to change a volatile variable to false to stop all the other threads from running. But for some reason the Time thread doesn't release the lock and other threads continue to run endlessly. </p>
  
  <p>Here is the code for the main class: </p>
  
  <pre><code>package cafesim;
  
  import java.time.Instant;
  import java.util.LinkedList;
  import java.util.Queue;
  import java.util.concurrent.locks.Condition;
  import java.util.concurrent.locks.ReentrantLock;
  
  
  public class CafeSim {
  
       public static volatile boolean continuetoRun = true;
  
      static Queue&lt;Customer&gt; OutsideQueue = new LinkedList&lt;Customer&gt;();
      static Queue&lt;Customer&gt; InsideQueue = new LinkedList&lt;Customer&gt;();
  
      static ReentrantLock QueueLock = new ReentrantLock();
      static Condition QueueCon = QueueLock.newCondition();
  
      public static void main(String[] args) {
  
          new Time(Instant.now().getEpochSecond()).start();
           new Table().start();
  
        }
  
  
      }
  
  }
  </code></pre>
  
  <p>Here is the code for the Table class:</p>
  
  <pre><code>public class Table extends Thread{
  
      String choice;
  
      public void run(){
  
  
         while(CafeSim.continuetoRun == true){
             CafeSim.QueueLock.lock();
  
  
            if(CafeSim.OutsideQueue.isEmpty() &amp;&amp; CafeSim.continuetoRun == true)
          try {
                 CafeSim.QueueCon.signal();
                 CafeSim.QueueCon.await();
  
             } catch (InterruptedException ex) {
                 Logger.getLogger(Table.class.getName()).log(Level.SEVERE, null, ex);
             } 
  
            else if(CafeSim.InsideQueue.size() == 10 &amp;&amp; CafeSim.continuetoRun == true){
                System.out.println("Seats inside filled, please wait!");
  
                try {
                 CafeSim.QueueCon.await();
             } catch (InterruptedException ex) {
                 Logger.getLogger(Table.class.getName()).log(Level.SEVERE, null, ex);
             } 
            }
  
  
            else if (CafeSim.OutsideQueue.size() != 0 &amp;&amp; CafeSim.continuetoRun == true){
                if(CafeSim.OutsideQueue.peek().choice == 1){
                 choice = "juice";
                  }
                else {
                 choice = "coffee";
                 }
  
                 System.out.println(CafeSim.OutsideQueue.peek() + " is at the table and has ordered " + choice + "!");       
                 CafeSim.InsideQueue.add(CafeSim.OutsideQueue.poll());
                 CafeSim.QueueCon.signal();
                 CafeSim.QueueLock.unlock();
            }  
            else {
                break;
            }
      }
  
         System.out.println("This should end[Table].");
         CafeSim.QueueCon.signal();
         CafeSim.QueueLock.unlock();
  
  
  }
  }
  </code></pre>
  
  <p>And here is the time class: </p>
  
  <pre><code>public class Time extends Thread{
  
      private long startTime;
      private long currentTime;
      boolean lastordersinformed = false;
  
  
      public Time(long timeatStart){
          this.startTime = timeatStart;
      }
  
      public void run(){
  
          while(CafeSim.continuetoRun == true){
              CafeSim.QueueLock.lock();
              currentTime = Instant.now().getEpochSecond();
  
              if(currentTime - startTime &lt; 20){
                  try {
                      CafeSim.QueueCon.signal();
                      CafeSim.QueueCon.await();
                  } catch (InterruptedException ex) {
                      Logger.getLogger(Time.class.getName()).log(Level.SEVERE, null, ex);
                  }
              }
  
              else if (currentTime - startTime &gt; 20 &amp;&amp; lastordersinformed == false){
  
                  System.out.println("LAST ORDERS RESTAURANT WILL CLOSE VERY SOON!");
                  CafeSim.OutsideQueue.clear();
                  //Waiter.timeToLeave = true;
                  lastordersinformed = true;
  
                  try {
                      CafeSim.QueueCon.signal();
                      CafeSim.QueueCon.await();
                  } catch (InterruptedException ex) {
                      Logger.getLogger(Time.class.getName()).log(Level.SEVERE, null, ex);
                  }
              }
  
              else if(currentTime - startTime &gt; 30 &amp;&amp; lastordersinformed == true){
  
                 CafeSim.continuetoRun = false;
                 System.out.println("Cafe is closed.");
  
              }
  
              else{
              try {
                      CafeSim.QueueCon.signal();
                      CafeSim.QueueCon.await();
                  } catch (InterruptedException ex) {
                      Logger.getLogger(Time.class.getName()).log(Level.SEVERE, null, ex);
                  }
              }
  
          }
  
        System.out.println("Thread has ended.[Time]");
        CafeSim.QueueCon.signal();
        CafeSim.QueueLock.unlock();
  
      }
  
  }
  </code></pre>
  
  <p>Both threads should end after 30 seconds, but for some reason they don't. Only the time thread comes to an end. </p>
  
  <p>Edit: I was able to fix it! </p>
  
  <p>I put while loops inside the run methods of my threads so that they would continue to run until a specific boolean was changed by the Time thread. Now during the while loop the .lock() was called multiple times by each thread and if a thread wants to release a lock at the end of its run method then it has to do .unlock() the same number of times that the lock was acquired. </p>
  
  <p>Declare a variable inside the thread: </p>
  
  <pre><code>int numberoftimesrun = 0;
  </code></pre>
  
  <p>Whenever you acquire the lock increment that variable:</p>
  
  <pre><code>CafeSim.QueueLock.lock();
  numberoftimesrun++;
  </code></pre>
  
  <p>Then at the end: </p>
  
  <pre><code> for (int i = 0; i &lt; numberoftimesrun; i++) {
               CafeSim.QueueLock.unlock();
          }
  </code></pre>