Java 如何使用信号量发送信号?

Java 如何使用信号量发送信号?,java,multithreading,concurrency,synchronization,semaphore,Java,Multithreading,Concurrency,Synchronization,Semaphore,现在我研究信号量。我在谷歌上搜索了以下关于这个主题的链接: 这个链接的作者写了关于使用信号量来发送信号的文章。为了展示它是如何工作的,他编写了自定义信号量 自定义信号灯代码: public class Semaphore { private boolean signal = false; public synchronized void take() { this.signal = true; this.notify(); } public synchroni

现在我研究信号量。我在谷歌上搜索了以下关于这个主题的链接:

这个链接的作者写了关于使用信号量来发送信号的文章。为了展示它是如何工作的,他编写了自定义信号量

自定义信号灯代码:

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...
    }
  }
}
主要内容:

据我所知,执行顺序如下

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");
        }
    }
}
因此,这不是我所期望的行为

我犯了一个错误,然后我写了代码或者我不理解这个概念


作者想说什么?

找到更好的教程

您看到的输出与我预期的差不多。发送方线程从不阻塞,因此它将永远继续打印发送、发送、发送。同时,在接收方线程中,每次调用semaphore.release方法时,它都会被阻止,直到发送方下次运行为止

我希望看到很多发送消息,偶尔也会收到消息——或多或少是你所说的看到的

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

一些作者提供了不做什么的示例,或者包含故意错误的示例,这些错误将在后面的示例中修复。你确定你没有效仿这样的例子吗


编辑:我跟踪了链接,看起来主要的问题是在take和release方法的定义中名称被交换了。如果您只是切换名称,这会更有意义。

找到更好的教程

您看到的输出与我预期的差不多。发送方线程从不阻塞,因此它将永远继续打印发送、发送、发送。同时,在接收方线程中,每次调用semaphore.release方法时,它都会被阻止,直到发送方下次运行为止

我希望看到很多发送消息,偶尔也会收到消息——或多或少是你所说的看到的

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

一些作者提供了不做什么的示例,或者包含故意错误的示例,这些错误将在后面的示例中修复。你确定你没有效仿这样的例子吗


编辑:我跟踪了链接,看起来主要的问题是在take和release方法的定义中名称被交换了。如果只是切换名称,则更有意义。

在ReceivesFore启动时,SendSeFore已经执行了10次

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


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

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

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


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

@rpg711 System.out对于了解线程执行顺序是不可靠的。试试Thread.sleep1000;在接收中的while循环之前。@rpg711 System.out无法可靠地了解线程的执行顺序。试试Thread.sleep1000;在接收中的while循环之前。请在i++<10时检查此链接{System.out.printlnsend;10-发送计数messages@gstackoverflow,我跟踪了链接,该页面上的信息完全错误。在上一个示例中,他演示了如何将信号量用作互斥对象,他在进入关键部分之前调用semaphore.take,在离开该部分时调用semaphore.release。但是take的行为nd release与它们应该的正好相反。take方法应该是等待的方法,release方法应该是通知的方法。在他的互斥体示例中,任何数量的线程都可以同时进入关键部分,但只有一个线程会再次退出。我甚至不会将本文称为“教程”。它只是一堆代码片段和一些注释,远远小于相应Java类的API文档,也就是说,在i++<10时将其与此链接进行比较并请检查{System.out.printlnsend;10-发送计数messages@gstackoverflow,我跟踪了链接,该页面上的信息完全错误。在上一个示例中,他演示了如何将信号量用作互斥对象,他在进入关键部分之前调用semaphore.take,在离开该部分时调用semaphore.release。但是take的行为nd释放与它们应该的正好相反。take方法应该是
等待,发布方法应该是通知的方法。在他的互斥体示例中,任何数量的线程都可以同时进入关键部分,但只有一个线程可以再次退出,我甚至不会将本文称为“教程”。它只是一堆代码片段和一些注释,比相应Java类的API文档要小得多,也就是说,将其与Java类进行比较,并且,我认为如果您多次运行此程序,在接收之前发送消息的数量并不总是相同的。即使使用倒计时锁存器,仅仅因为您同时启动线程,并不意味着它们每次都以相同的方式执行。我只想介绍一个线程;在发送方开始时延迟它,以确保接收方在第一次发送之前先等待。@maxmil无论如何,代码不应依赖于Thread.sleep。这个概念是错误的。而且,我认为如果你多次运行这个程序,在接收之前发送消息的数量并不总是相同的。即使使用倒计时锁存器,仅仅因为您同时启动线程,并不意味着它们每次都以相同的方式执行。我只想介绍一个线程;在发送方开始时延迟它,以确保接收方在第一次发送之前先等待。@maxmil无论如何,代码不应依赖于Thread.sleep。这个概念是错误的。
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