Java semaphore implementation

Question:

1 Stream:

public class First implements Runnable {
    private Semaphore semaphore;

    public First(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run(){
        for (int i = 0; i < 5; i++) {
            semaphore.enter();
            System.out.println(1);
            semaphore.leave();
        }
    }
}

2 stream:

public class Second implements Runnable {
    private Semaphore semaphore;

    public SequentalCleaner(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run(){
        for (int i = 0; i < 5; i++) {
            semaphore.enter();
            System.out.println(2);
            semaphore.leave();
        }
    }
}

Traffic light:

public class Semaphore {
    private int cur;

    public Semaphore(int cur) {
        this.cur = cur;
    }

    public void enter() {
        while(cur == 0){
        }
            --cur;
    }
    public void leave(){
        ++cur;
    }
}

It's out of sync. How to make it synchronized? Output when starting streams:

2 1 2 1 2 1 1 1

or for example

1 1 1 1 1 2 2 2 2 2

Those. they don't even finish their job.

Answer:

Although, of course, it is better to look at the implementation options for semaphores in books on multithreading, here is the "bicycle" version:

public class TestSemaphor {
    private final static int NThreads = 60;

public static void main(String[] args) {
    Semaphore semaphore = new Semaphore(3);

    Thread[] threads = new Thread[NThreads];
    for (int i = 0; i < NThreads; i++) {
        threads[i] = new Thread(new Runner(semaphore, i));
    }
    for (int i = 0; i < NThreads; i++) {
        threads[i].start();
    }
}
}

class Runner implements Runnable {
private Semaphore semaphore;
private int label;

public Runner(Semaphore semaphore, int label) {
    this.semaphore = semaphore;
    this.label = label;
}

@Override
public void run() {
    int r = 0;
    System.out.println("thread " + label + " start");

    semaphore.enter();
    System.out.println("thread " + label + "  is working");
    for (int k = 0; k < 10000; k++) {
        r = new Random().nextInt();
    }
    ;
    System.out.println("thread " + label + "  has ended work");
    semaphore.leave();

    System.out.println("thread " + label + " end " + r);
}
}

class Semaphore {
private int curMax;
private int cur;
private Object lock = new Object();

public Semaphore(int curMax) {
    this.curMax = curMax;
}

public void enter() {
    synchronized (lock) {
        cur++;
        if (cur > curMax) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }

}

public void leave() {
    synchronized (lock) {
        cur--;
        lock.notify();
    }

}
}

Actually, the idea is this: synchronization is used only to update the queue counter. If at the same time we have more threads than necessary, then we send the current thread to waiting. When freeing the semaphore, we call notify on a random waiting thread. Note that synchronization goes on the same object – that's why happens before is present

Scroll to Top