Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write simple fair semaphore?

I found simple realization of semaphore(my CustomSemaphore) and as I understand this is 'not fair' one because into secure block can enter only first thread all time(I am not sure). How can I write fair semaphore(analog of concurrency new Semaphore(1, true);)

   public class SimpleSemaphoreSample2 {
    CustomSemaphore cSem = new CustomSemaphore(1);

    public static void main(String[] args) {
        SimpleSemaphoreSample2 main = new SimpleSemaphoreSample2();
        Semaphore sem = new Semaphore(1, true);
        Thread thrdA = new Thread(main.new SyncOutput(sem, "Thread1"), "Thread1");
        Thread thrdB = new Thread(main.new SyncOutput(sem, "Thread2"), "Thread2");

        thrdA.start();
        thrdB.start();

        try {
            thrdB.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("END");
    }

    class SyncOutput implements Runnable {
        private Semaphore sem;
        private String msg;

        public SyncOutput(Semaphore s, String m) {
            sem = s;
            msg = m;
        }

        @Override
        public void run() {
            while (true) {
                try {
//                  sem.acquire();
                    cSem.acquire();
                    System.out.println("Before");
                    Thread.sleep(500);
                    System.out.println(msg);
                    Thread.sleep(500);
                    System.out.println("After");
                    Thread.sleep(500);
                } catch (Exception exc) {
                    exc.printStackTrace();
                }
//              sem.release();
                cSem.release();
            }
        }
    }

    public class CustomSemaphore {
        private int counter;

        public CustomSemaphore() {
            this(0);
        }

        public CustomSemaphore(int i) {
            if (i < 0)
                throw new IllegalArgumentException(i + " < 0");
            counter = i;
        }

        public synchronized void release() {
            if (counter == 0) {
                this.notify();
            }
            counter++;
        }

        public synchronized void acquire() throws InterruptedException {
            while (counter == 0) {
                this.wait();
            }
            counter--;
        }
    }
}
enter code here
like image 524
user1074896 Avatar asked Mar 29 '12 15:03

user1074896


People also ask

What is a fair semaphore?

Generally, semaphores used to control resource access should be initialized as fair, to ensure that no thread is starved out from accessing a resource. When using semaphores for other kinds of synchronization control, the throughput advantages of non-fair ordering often outweigh fairness considerations.

What is an example of a semaphore?

An oxygen thread will wait for two hydrogen to come ready and then signal the oxygen count twice to let them know oxygen is ready. This is an example of a "rendezvous"—we are signaling a general semaphore to record the action of one thread and another thread can wait on it to meet up with it.

What is semaphore in Java with example?

Semaphore in Java It is a type of variable which is used to manage concurrent processes and also synchronize them. It is also used to avoid race conditions. It restricts the number of threads to access a shared resource. For example, we can restrict a file to access up to 10 connections simultaneously.

How do you use a semaphore?

In general, to use a semaphore, the thread that wants access to the shared resource tries to acquire a permit. If the semaphore's count is greater than zero, then the thread acquires a permit, which causes the semaphore's count to be decremented. Otherwise, the thread will be blocked until a permit can be acquired.


2 Answers

Your semaphore is not fair because it is possible that a thread wait forever. Think about a mutex (binary semaphore) used to write a value by 3 threads. T1 acquire, T2 wait and T3 wait. Now during release, you notify and one between T2 and T3 take the semaphore (let say T2). Now T1 come back and wait. When T2 notify, T1 takes it. It can happen as many times as possible, and T3 will never have the semaphore.

One change can be to use a simple FIFO inside the semaphore. When an thread has to wait, you add his id in the Queue. Now when you notify, you notify to all the threads. The only thread which progress is the one which is at the head of the queue.

like image 60
UmNyobe Avatar answered Oct 19 '22 00:10

UmNyobe


According to Java Concurrency In Practice it states that

intrinsic locking offers no deterministic fairness guarantees

Intrinsic locking here is using synchronized. So there is no way you can make this Semaphore example fair without replacing synchronized with Lock lock = new ReentrantLock(true);

Where the true as constructor argument tells the ReentrantLock to be fair

Edit based on a comment by @trutheality

If you really want it to be correct without using the ReentrantLock, you can implement the Semaphore inheriting the synchronization primitives from the AbstractQueuedSynchronizer. This would prove to be quite complicated and if you can correctly write it with ReentrantLock I would suggest that. Note: ReentrantLock delegates its synchronization to the AQS.

like image 26
John Vint Avatar answered Oct 19 '22 00:10

John Vint