Как использовать семафоры для сигнализации?

1

Теперь я исследую семафоры. Я googled по ссылке на эту тему:

ссылка

Автор этой ссылки писал об использовании семафоров для сигнализации. Чтобы показать, как это работает, он написал собственный семафор.

пользовательский код семафора:

public class Semaphore {
  private boolean signal = false;

  public synchronized void take() {
    this.signal = true;
    this.notify();
  }

  public synchronized void release() throws InterruptedException{
    while(!this.signal) wait();
    this.signal = false;
  }

}

о том, как использовать его в коде, который он написал:

public class SendingThread {
  Semaphore semaphore = null;

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

  public void run(){
    while(true){
      //do something, then signal
      this.semaphore.take();

    }
  }
}



public class RecevingThread {
  Semaphore semaphore = null;

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

  public void run(){
    while(true){
      this.semaphore.release();
      //receive signal, then do something...
    }
  }
}

главный:

Semaphore semaphore = new Semaphore();

SendingThread sender = new SendingThread(semaphore);

ReceivingThread receiver = new ReceivingThread(semaphore);

receiver.start();
sender.start();

Как я понял, порядок исполнения должен быть следующим

send - receive
send - receive
send - receive
...

Я попытался написать собственный код, используя эту bluerprint

public class SendReceiveWithCustomSemaphore {
    public static void main(String[] args) {
        MySemaphore mySemaphore = new MySemaphore();
        new Send(mySemaphore).start();
        new Receive(mySemaphore).start();
    }
}

class MySemaphore {
    boolean flag = false;

    public synchronized void take() throws InterruptedException {
        flag = true;
        notify();
    }

    public synchronized void release() throws InterruptedException {
        while (!flag) {
            wait();
        }
        flag = false;
    }
}

class Send extends Thread {
    MySemaphore mySemaphore;

    public Send(MySemaphore semaphore) {
        this.mySemaphore = semaphore;
    }

    @Override
    public void run() {
        int i = 0;
        while (i++ < 10) {
            System.out.println("send");
            try {
                mySemaphore.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Receive extends Thread {
    MySemaphore mySemaphore;

    public Receive(MySemaphore semaphore) {
        this.mySemaphore = semaphore;
    }

    @Override
    public void run() {
        while (true) {
            try {
                mySemaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("receive");
        }
    }
}

вывод:

send
send
send
send
send
send
send
send
send
send
receive

Таким образом, для меня не ожидается поведения.

Я сделал ошибку, тогда я написал код, или я не понял концепцию?

Что хотел сказать автор?

  • 0
    @ rpg711 ideone.com/d76Elw
  • 0
    System.out не является надежным для определения порядка выполнения потока. stackoverflow.com/a/18831093/1168342
Показать ещё 1 комментарий
Теги:
multithreading
semaphore
concurrency
synchronization

2 ответа

4
Лучший ответ

Найдите лучший учебник.

Результат, который вы видите, о том, чего я ожидаю. Нить "отправитель" никогда не блокируется, поэтому он будет печатать "отправить", "отправить", "отправить" навсегда. Между тем, в потоке "получателя" каждый раз, когда он вызывает метод semaphore.release(), он будет заблокирован до следующего запуска отправителя.

Я бы ожидал увидеть множество "отправки" сообщений, причем случайные "получаемые" сообщения смешивались в --- более или менее то, что вы описываете.

Я не знаю, что должен доказать этот пример, но для меня создается впечатление, что автор не знает, как программисты ожидают, что Семафоры будут себя вести.

Некоторые авторы приводят примеры того, что не делать, или примеры, содержащие намеренную ошибку, которая будет "исправлена" в более позднем примере. Вы уверены, что не следуете примеру такого рода?

Изменение: я пошел по ссылке, и похоже, что основная проблема заключается в том, что имена были заменены определениями методов take() и release(). Если вы просто переключаете имена, это имеет смысл.

  • 0
    tutorials.jenkov.com/java-concurrency/semaphores.html
  • 0
    пожалуйста, проверьте эту ссылку
Показать ещё 5 комментариев
1

К моменту получения ReceiveSemafore SendSemafore уже выполнен 10 раз.

Рассмотрите возможность использования CountDownLatch для запуска двух потоков одновременно. Хотя, как указано Fuhrmanator, это не приведет к альтернативному выходу, который вы ищете.

Для этого я бы использовал ограниченный семафор с одним сигналом.

  • 0
    Кроме того, я бы сказал, что если вы запускаете эту программу несколько раз, она не всегда будет иметь одинаковое количество отправляемых сообщений до получения. Даже с CountDownLatch, просто потому что вы запускаете потоки одновременно, это не значит, что они будут выполняться одинаково каждый раз. Я бы просто представил Thread.sleep(1000); в начале отправителя, чтобы задержать его (чтобы убедиться, что получатель ждет в первую очередь, прежде чем он сделает свою первую отправку).
  • 0
    @maxmil в любом случае код не должен полагаться на Thread.sleep (). Концепция неверна.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню