Реализация семафора Java

431
29 октября 2017, 17:41

1 Поток:

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 поток:

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();
        }
    }
}

Семафор:

public class Semaphore {
    private int cur;
    public Semaphore(int cur) {
        this.cur = cur;
    }
    public void enter() {
        while(cur == 0){
        }
            --cur;
    }
    public void leave(){
        ++cur;
    }
}

Это не синхронизировано. Как сделать синхронизированным? Вывод при запуске потоков:

2 1 2 1 2 1 1 1

или, например

1 1 1 1 1 2 2 2 2 2

Т.е. они даже не заканчивают свою работу.

Answer 1

Хотя конечно варианты реализации семафоров лучше в книгах по многопоточности посмотреть, вот вариант "велосипеда":

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();
    }
}
}

Собственно идея такая: синхронизации используется только для того, чтобы обновить счетчик очереди. Если при этом у нас потоков больше чем надо, то отправляем текущий поток в ожидание. При освобождении семафора вызываем на случайном ожидающем потоке notify. Обратите внимание что синхронизация идет по одному и тому же объекту - поэтому happens before присутствует

READ ALSO
Получение данных в запросе Spring, js/axios

Получение данных в запросе Spring, js/axios

ЗдравствуйтеПишу SPA приложение на бекенде есть Spring и вот такой метод в контроллере

349
A have an error when I call web service [требует правки]

A have an error when I call web service [требует правки]

InternalError occured : Error occured while invoking reflection on target classesMake sure all referenced classes are on classpath: interface javax

425
как правильно задать цикл

как правильно задать цикл

ЗдравствуйтеНужно написать код, решающий

354
JavaFx обработка выхода из компонента TextField

JavaFx обработка выхода из компонента TextField

Как отследить в компоненте TextField, что курсор не в немЭто нужно для проверки значений в реестрации

342