【问题标题】:How to use Semaphores for Signaling?如何使用信号量进行信令?
【发布时间】:2014-04-23 21:12:24
【问题描述】:

现在我研究信号量。我搜索了有关此主题的以下链接:

link

此链接的作者撰写了有关使用信号量进行信号传输的文章。为了展示它是如何工作的,他编写了自定义信号量。

自定义信号量代码:

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
...

我尝试使用此蓝图编写自己的代码

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

因此,这不是我预期的行为。

是我写错了代码还是没看懂概念?

作者想说什么?

【问题讨论】:

标签: java multithreading concurrency synchronization semaphore


【解决方案1】:

找到更好的教程。

您看到的输出与我预期的差不多。 “sender”线程永远不会阻塞,所以它会一直打印“send”、“send”、“send”。同时,在“receiver”线程中,每次调用 semaphore.release() 方法时,都会阻塞,直到下一次 sender 开始运行。

我希望看到很多“发送”消息,偶尔会混入“接收”消息——或多或少与您所描述的一样。

我不知道这个例子应该证明什么,但对我来说,它给人的印象是作者不知道程序员期望信号量如何表现。

一些作者提供了应该做的例子,或者包含将在后面的例子中“修复”的故意错误的例子。你确定你不是在效仿这种例子吗?

编辑:我点击了链接,看起来主要问题是在 take() 和 release() 方法的定义中交换了名称。如果只是换个名字,那就更有意义了。

【讨论】:

  • 请查看此链接
  • while (i++
  • 10 - 发送消息计数
  • @gstackoverflow,我点击了链接,该页面上的信息是错误的。在最后一个示例中,他展示了如何将信号量用作互斥体,他在进入临界区之前调用 semaphore.take() 并在离开临界区时调用 semaphore.release()。但是 take() 和 release() 的行为与它们应该是完全相反的。 take() 方法应该是等待的方法,而 release() 方法应该是通知的方法。在他的互斥锁示例中,任意数量的线程可以同时进入临界区,但只有一个线程会再次退出。
  • 我什至不会称这篇文章为“教程”。只是一堆代码片段和一些cmet远远小于对应Java类的API文档,即对比SemaphoreCountDownLatch
【解决方案2】:

到 ReceiveSemafore 启动时,SendSemafore 已经执行了 10 次。

考虑使用CountDownLatch 同时启动两个线程。尽管正如 Fuhrmanator 指出的那样,这不会产生您正在寻找的交替输出。

为此,我将使用带一个信号的有界信号量。

【讨论】:

  • 另外,我认为如果你多次运行这个程序,在接收之前它不会总是相同数量的“发送”消息。即使使用 CountDownLatch,仅仅因为您同时启动线程,并不意味着它们每次都会以相同的方式执行。我会简单地在发送者的开头引入一个Thread.sleep(1000); 来延迟它(以确保接收者在第一次发送之前先等待)。
  • @maxmil 无论如何代码不应该依赖于 Thread.sleep()。概念是错误的。
猜你喜欢
  • 1970-01-01
  • 2012-10-07
  • 2015-04-13
  • 1970-01-01
  • 1970-01-01
  • 2017-10-03
  • 2011-07-29
  • 1970-01-01
相关资源
最近更新 更多