Search code examples
javaspring-bootmultithreadingreentrantlock

Java: Program to allow people through a Gate


I am writing a program to do a gate count of 5, and then allow people into the building (by doing a System.out.println).

I have the following solution, using synchronized. However, someone mentioned this solution does not allow for sequential lock fairness, for people in line. How can I rewrite this to allow for it? Is semaphores below correct?

Using Synchronized:

public class LineCount {

    int totalInLine = 0;

    public synchronized void addToLine() {
        totalInLine = totalInLine + 1;
        if (totalInLine == 5) {
             System.out.println("People may enter");
             totalInLine = 0;
        }
    }

Using Semaphore:

public class LineCount {

    Semaphore semaphore = new Semaphore(5, true);

    public void addToLine() throws InterruptedException {

        semaphore.acquire();
        if (semaphore.availablePermits() == 0) {
            System.out.println("People may enter");
            semaphore.release(5);
            semaphore = new Semaphore(5, true);
        }
    }
}

Solution

  • The Semaphore version is almost, but not quite the same as the synchronized version. But, the Semaphore version isn't thread safe. I suggest two changes:

    public class LineCount {
    
        final Semaphore semaphore = new Semaphore(5, true);   // added `final` keyword
    
        public void addToLine() throws InterruptedException {
            semaphore.acquire();
            if (semaphore.availablePermits() == 0) {
                System.out.println("People may enter");
                semaphore.release(5);
             // semaphore = new Semaphore(5, true);           // **Don't Do This**
            }
        }
    }
    

    The reason is, if some thread A executes the semaphore.release(5) statement, then thread B could slip in, and decrement the old Semaphore before thread A's semaphore = new Semaphore(...) assignment takes effect. That would allow more than five calls before the next time the message is printed.

    There is no need to create a new Semaphore because each release(5) call will allow five more calls to acquire a permit.

    The reason for final is mostly just to make sure that everybody who reads the code will immediately understand that semaphore always will refer to the same object.


    Update:

    However, someone mentioned [that the synchronized] solution does not allow for sequential lock fairness, for people in line.

    I can't even guess what that means. You should ask "someone" for clarity.

    Your synchronized version of addToLine prints a message on every fifth call. It doesn't do anything else. It doesn't make any caller wait for any longer than it takes some other caller to print the message. Where is the "unfairness" in that?

    The title of your question is "Program to allow people through a gate." But there's nothing here that really models a gate. There's nothing in it that makes any "person" wait for the "gate" to "open." It's literally just a thread-safe method that prints a certain message on every fifth call.