guitar138
guitar138

Reputation: 33

Semaphores and counting with java

I've written out my code signalling north and southbound cars crossing a one lane bridge but I'm having some trouble with counting.

It should read like: a car is waiting, then maybe several, with one crossing at a time and increasing every time. Instead it repeats the same three numbers every time.

Should I declare my count int differently or am I increasing it incorrectly? I've tried many different ways and can't quite find the true issue.

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

public class SingleLaneBridge {

public static void main(String[] args) {
  final Bridge bridge = new Bridge();

  Thread th1 = new Thread( new Runnable() {

    @Override
    public void run() {
      while(true) {
        Car car = new Car(bridge);
        Thread th = new Thread(car);
        th.start();
        try {
          Thread.sleep(5000);
        } catch (InterruptedException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
    }
    });

    Thread th2 = new Thread( new Runnable() {

      @Override
      public void run() {
        while(true) {
          Car car = new Car(bridge);
          Thread th = new Thread(car);
          th.start();
          try {
            Thread.sleep(5000);
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }
      }
      });

      th1.start();
      th2.start();
    }
  }

  class Bridge {
    private final Semaphore semaphore;
    public Bridge() {
    semaphore = new Semaphore(1);
  }
  public void crossBridge(Car car) {
    try {
      System.out.printf("Car %s is trying to cross the bridge.           \n",car.count++);
      semaphore.acquire();
      System.out.printf("Car %s is crossing the bridge. \n",car.count++);
      Thread.sleep(5000);
    } catch(InterruptedException iex) {
      iex.printStackTrace();
    } finally {
      System.out.printf(" Car %s has crossed the bridge. \n",car.count++);
      semaphore.release();
    }
  }
}

class Car implements Runnable {
  int count = 0;
  private String name;
  private Bridge bridge;

  public Car(Bridge bridge) {
    this.bridge = bridge;
  }
  public void run() {
    bridge.crossBridge(this);
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

Upvotes: 0

Views: 1246

Answers (1)

Sathish
Sathish

Reputation: 5173

The reason why it repeats the three numbers again and again is that, the Car instances are created afresh every time and the count is initialized to 0.

To overcome this, define the Car class as follows to get the atomic counting as multiple Threads (Cars) are involved here,

class Car implements Runnable {
    private static AtomicInteger globalCarID = new AtomicInteger(0); 
    int count;
    ...

    public Car(Bridge bridge) {
        this.bridge = bridge;
        count = globalCarID.incrementAndGet();
    }
}

And modify the System.out.printf's in crossBridge() method to not to increment the count,

Below is the complete code that might serve what you wanted,

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class SingleLaneBridge {

    public static void main(String[] args) {
        final Bridge bridge = new Bridge();

        Thread th1 = new Thread( new Runnable() {

        public void run() {
            while(true) {
                Car car = new Car(bridge);
                Thread th = new Thread(car);
                th.start();
                try {
                  Thread.sleep(5000);
                } catch (InterruptedException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
                }
            }
        }
        });

        Thread th2 = new Thread( new Runnable() {

        public void run() {
            while(true) {
                Car car = new Car(bridge);
                Thread th = new Thread(car);
                th.start();
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        });

        th1.start();
        th2.start();
    }
}

class Bridge {
    private final Semaphore semaphore;
    public Bridge() {
        semaphore = new Semaphore(1);
    }

    public void crossBridge(Car car) {
        try {
            System.out.printf("Car %s is trying to cross the bridge. \n",car.count);
            semaphore.acquire();
            System.out.printf("Car %s is crossing the bridge. \n",car.count);
            Thread.sleep(500);
        } catch(InterruptedException iex) {
            iex.printStackTrace();
        } finally {
            System.out.printf(" Car %s has crossed the bridge. \n",car.count);
            semaphore.release();
        }
    }
}   

class Car implements Runnable {
    private static AtomicInteger globalCarID = new AtomicInteger(0); 
    int count;
    private String name;
    private Bridge bridge;

    public Car(Bridge bridge) {
        this.bridge = bridge;
        count = globalCarID.incrementAndGet();
    }

    public void run() {
        bridge.crossBridge(this);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Upvotes: 1

Related Questions