Теперь я исследую семафоры. Я 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
Таким образом, для меня не ожидается поведения.
Я сделал ошибку, тогда я написал код, или я не понял концепцию?
Что хотел сказать автор?
Найдите лучший учебник.
Результат, который вы видите, о том, чего я ожидаю. Нить "отправитель" никогда не блокируется, поэтому он будет печатать "отправить", "отправить", "отправить" навсегда. Между тем, в потоке "получателя" каждый раз, когда он вызывает метод semaphore.release(), он будет заблокирован до следующего запуска отправителя.
Я бы ожидал увидеть множество "отправки" сообщений, причем случайные "получаемые" сообщения смешивались в --- более или менее то, что вы описываете.
Я не знаю, что должен доказать этот пример, но для меня создается впечатление, что автор не знает, как программисты ожидают, что Семафоры будут себя вести.
Некоторые авторы приводят примеры того, что не делать, или примеры, содержащие намеренную ошибку, которая будет "исправлена" в более позднем примере. Вы уверены, что не следуете примеру такого рода?
Изменение: я пошел по ссылке, и похоже, что основная проблема заключается в том, что имена были заменены определениями методов take() и release(). Если вы просто переключаете имена, это имеет смысл.
К моменту получения ReceiveSemafore SendSemafore уже выполнен 10 раз.
Рассмотрите возможность использования CountDownLatch для запуска двух потоков одновременно. Хотя, как указано Fuhrmanator, это не приведет к альтернативному выходу, который вы ищете.
Для этого я бы использовал ограниченный семафор с одним сигналом.
Thread.sleep(1000);
в начале отправителя, чтобы задержать его (чтобы убедиться, что получатель ждет в первую очередь, прежде чем он сделает свою первую отправку).