Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用按钮启动和停止线程_Java_Multithreading_Swing_Concurrency - Fatal编程技术网

Java 使用按钮启动和停止线程

Java 使用按钮启动和停止线程,java,multithreading,swing,concurrency,Java,Multithreading,Swing,Concurrency,我有一个我认为很简单的问题,我还没有找到一个好的解决方案:我希望能够通过点击Swing界面面板上的按钮来暂停和取消线程中发生的活动 具体来说,我想使用一个线程来实时接收音频帧;第二线程,用于对这些帧执行魔术处理;第三个线程序列化结果并通过套接字发送到其他地方。更重要的是,根据我们使用的魔术品牌,第二个线程中的处理每帧执行的时间可能比实际的数据收集要长,并且数据可能会在一段时间后堆积起来 作为一个非常粗糙的原型解决方案,我们想我们应该添加一个GUI,带有一个按钮来打开和关闭音频采集过程,以及一个状

我有一个我认为很简单的问题,我还没有找到一个好的解决方案:我希望能够通过点击Swing界面面板上的按钮来暂停和取消线程中发生的活动

具体来说,我想使用一个线程来实时接收音频帧;第二线程,用于对这些帧执行魔术处理;第三个线程序列化结果并通过套接字发送到其他地方。更重要的是,根据我们使用的魔术品牌,第二个线程中的处理每帧执行的时间可能比实际的数据收集要长,并且数据可能会在一段时间后堆积起来

作为一个非常粗糙的原型解决方案,我们想我们应该添加一个GUI,带有一个按钮来打开和关闭音频采集过程,以及一个状态栏(稍后实现),以便用户可以关注缓冲区(链接的阻塞队列)有多满

这比我预想的要难。我已经将问题简化为一个玩具版本:一个可以存储50个整数的链接阻塞队列、一个GUI、两个线程(以不同的速率添加到队列和从队列中移除)以及一个围绕布尔值的令牌对象。它看起来是这样的,而且有点像:

Test.java

public class Test {
  public static void main(String[] args) throws IOException {

    Token t1 = new Token();
    Token t2 = new Token();
    LinkedBlockingQueue<Integer> lbq = new LinkedBlockingQueue<Integer>(50);

    startFill sf = new startFill(t1, lbq);
    startEmpty se = new startEmpty(t2, lbq);

    TestUI testUI = new TestUI(t1, t2, lbq);
    testUI.setVisible(true);

    sf.start();
    se.start();
  }
}
public class TestUI extends JFrame implements ActionListener {
  private JToggleButton fillStatus, emptyStatus;
  public boolean filling, emptying;
  public Token t1, t2;
  public LinkedBlockingQueue<Integer> lbq;

  public TestUI(Token t1, Token t2, LinkedBlockingQueue<Integer> lbq) {
    this.t1 = t1;
    this.t2 = t2;
    this.lbq = lbq;
    initUI();
  }

  public synchronized void initUI() {
    JPanel panel = new JPanel();
    panel.setLayout(null);

    filling = false;
    fillStatus = new JToggleButton("Not Filling");
    fillStatus.setBounds(20, 20, 150, 25);
    fillStatus.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        if (filling == false) {
          fillStatus.setText("Filling");
        } else {
          fillStatus.setText("Not Filling");
        }
        filling = !filling;
        t1.flip();
        System.out.println("fill button press");
      }
    });

// Similar code for actionListener on Empty button, omitted

    panel.add(fillStatus);
    panel.add(emptyStatus);
    add(panel);
    setTitle("Test interface");
    setSize(420, 300);
    setLocationByPlatform(true);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public void actionPerformed(ActionEvent e) {
  }
}
public class startFill extends Thread {
  public Token token;
  public LinkedBlockingQueue<Integer> lbq;

  public startFill(Token token, LinkedBlockingQueue<Integer> lbq) {
    this.token = token;
    this.lbq = lbq;
  }

  public void run() {
    int count = 0;
    while (true) {
      while (!token.running()) {
        try {
          sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }

      while (token.running()) {
        try {
          lbq.put(count);
          System.out.println("queue size = " + lbq.size());
          count++;
          sleep(100);
        } catch (InterruptedException e1) {
          e1.printStackTrace();
        }
      }
    }
  }
}
公共类测试{
公共静态void main(字符串[]args)引发IOException{
令牌t1=新令牌();
令牌t2=新令牌();
LinkedBlockingQueue lbq=新LinkedBlockingQueue(50);
startFill sf=新的startFill(t1,lbq);
Startetty se=新Startetty(t2,lbq);
TestUI TestUI=新的TestUI(t1、t2、lbq);
testUI.setVisible(true);
sf.start();
se.start();
}
}
TestUI.java

public class Test {
  public static void main(String[] args) throws IOException {

    Token t1 = new Token();
    Token t2 = new Token();
    LinkedBlockingQueue<Integer> lbq = new LinkedBlockingQueue<Integer>(50);

    startFill sf = new startFill(t1, lbq);
    startEmpty se = new startEmpty(t2, lbq);

    TestUI testUI = new TestUI(t1, t2, lbq);
    testUI.setVisible(true);

    sf.start();
    se.start();
  }
}
public class TestUI extends JFrame implements ActionListener {
  private JToggleButton fillStatus, emptyStatus;
  public boolean filling, emptying;
  public Token t1, t2;
  public LinkedBlockingQueue<Integer> lbq;

  public TestUI(Token t1, Token t2, LinkedBlockingQueue<Integer> lbq) {
    this.t1 = t1;
    this.t2 = t2;
    this.lbq = lbq;
    initUI();
  }

  public synchronized void initUI() {
    JPanel panel = new JPanel();
    panel.setLayout(null);

    filling = false;
    fillStatus = new JToggleButton("Not Filling");
    fillStatus.setBounds(20, 20, 150, 25);
    fillStatus.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        if (filling == false) {
          fillStatus.setText("Filling");
        } else {
          fillStatus.setText("Not Filling");
        }
        filling = !filling;
        t1.flip();
        System.out.println("fill button press");
      }
    });

// Similar code for actionListener on Empty button, omitted

    panel.add(fillStatus);
    panel.add(emptyStatus);
    add(panel);
    setTitle("Test interface");
    setSize(420, 300);
    setLocationByPlatform(true);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public void actionPerformed(ActionEvent e) {
  }
}
public class startFill extends Thread {
  public Token token;
  public LinkedBlockingQueue<Integer> lbq;

  public startFill(Token token, LinkedBlockingQueue<Integer> lbq) {
    this.token = token;
    this.lbq = lbq;
  }

  public void run() {
    int count = 0;
    while (true) {
      while (!token.running()) {
        try {
          sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }

      while (token.running()) {
        try {
          lbq.put(count);
          System.out.println("queue size = " + lbq.size());
          count++;
          sleep(100);
        } catch (InterruptedException e1) {
          e1.printStackTrace();
        }
      }
    }
  }
}
公共类TestUI扩展JFrame实现ActionListener{
私有JToggleButton填充状态,清空状态;
公共布尔填充、清空;
公共令牌t1、t2;
公共链接锁定队列lbq;
公共测试UI(令牌t1、令牌t2、LinkedBlockingQueue lbq){
这是1.t1=t1;
这1.t2=t2;
这个。lbq=lbq;
initUI();
}
公共同步的void initUI(){
JPanel面板=新的JPanel();
panel.setLayout(空);
填充=假;
fillStatus=新的JToggleButton(“未填充”);
填充状态.立根(20,20,150,25);
fillStatus.addActionListener(新ActionListener(){
已执行的公共无效操作(操作事件){
如果(填充==假){
fillStatus.setText(“填充”);
}否则{
fillStatus.setText(“未填充”);
}
填充=!填充;
t1.flip();
System.out.println(“填充按钮按下”);
}
});
//空按钮上actionListener的类似代码,省略
面板。添加(填充状态);
面板。添加(清空状态);
添加(面板);
setTitle(“测试接口”);
设置大小(420300);
setLocationByPlatform(真);
setDefaultCloseOperation(关闭时退出);
}
已执行的公共无效操作(操作事件e){
}
}
startFill.java

public class Test {
  public static void main(String[] args) throws IOException {

    Token t1 = new Token();
    Token t2 = new Token();
    LinkedBlockingQueue<Integer> lbq = new LinkedBlockingQueue<Integer>(50);

    startFill sf = new startFill(t1, lbq);
    startEmpty se = new startEmpty(t2, lbq);

    TestUI testUI = new TestUI(t1, t2, lbq);
    testUI.setVisible(true);

    sf.start();
    se.start();
  }
}
public class TestUI extends JFrame implements ActionListener {
  private JToggleButton fillStatus, emptyStatus;
  public boolean filling, emptying;
  public Token t1, t2;
  public LinkedBlockingQueue<Integer> lbq;

  public TestUI(Token t1, Token t2, LinkedBlockingQueue<Integer> lbq) {
    this.t1 = t1;
    this.t2 = t2;
    this.lbq = lbq;
    initUI();
  }

  public synchronized void initUI() {
    JPanel panel = new JPanel();
    panel.setLayout(null);

    filling = false;
    fillStatus = new JToggleButton("Not Filling");
    fillStatus.setBounds(20, 20, 150, 25);
    fillStatus.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent event) {
        if (filling == false) {
          fillStatus.setText("Filling");
        } else {
          fillStatus.setText("Not Filling");
        }
        filling = !filling;
        t1.flip();
        System.out.println("fill button press");
      }
    });

// Similar code for actionListener on Empty button, omitted

    panel.add(fillStatus);
    panel.add(emptyStatus);
    add(panel);
    setTitle("Test interface");
    setSize(420, 300);
    setLocationByPlatform(true);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
  }

  public void actionPerformed(ActionEvent e) {
  }
}
public class startFill extends Thread {
  public Token token;
  public LinkedBlockingQueue<Integer> lbq;

  public startFill(Token token, LinkedBlockingQueue<Integer> lbq) {
    this.token = token;
    this.lbq = lbq;
  }

  public void run() {
    int count = 0;
    while (true) {
      while (!token.running()) {
        try {
          sleep(200);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }

      while (token.running()) {
        try {
          lbq.put(count);
          System.out.println("queue size = " + lbq.size());
          count++;
          sleep(100);
        } catch (InterruptedException e1) {
          e1.printStackTrace();
        }
      }
    }
  }
}
public类startFill扩展线程{
公共令牌;
公共链接锁定队列lbq;
公共startFill(令牌、LinkedBlockingQueue lbq){
this.token=token;
这个。lbq=lbq;
}
公开募捐{
整数计数=0;
while(true){
而(!token.running()){
试一试{
睡眠(200);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
while(token.running()){
试一试{
lbq.put(计数);
System.out.println(“队列大小=“+lbq.size());
计数++;
睡眠(100);
}捕捉(中断异常e1){
e1.printStackTrace();
}
}
}
}
}
还有一个startetty.java,它的工作方式与之类似,还有一个Token.java,它是布尔状态变量的包装器,为了简洁起见省略了它

这样做是可行的,但代价是(!token.running())循环中的轮询。 我尝试使用锁和条件,但失败了,总是得到非法的MonitorStateException

我看到了这个,并设法让它工作起来,但是以使用yield()方法为代价,这个方法在Java5和Java6之间明显不同,而且似乎非常不鼓励

因此,我的问题是:是否有正确或明显更好的方法来完成我正在尝试做的事情?似乎应该有一种方法可以实现这一点,而无需使用轮询和可靠的方法


更新:我不确定是否可以通过某种方式解决应用程序的音频捕获环路控制问题。无论是人类按下按钮,还是内部逻辑基于其他因素做出决策,我们都需要能够关闭这该死的东西,让它在命令下恢复生机

除了通过GUI手动处理3个工作进程之间的同步外,您还可以在工作进程之间设置工厂列表:

  • 在工作人员之间添加2个队列
  • 在队列状态条件下阻止线程;
    • 空队列上的读卡器(使用者)块
    • 写入程序(生产者)在队列已满时阻塞(例如2n条消息,其中n是该队列的使用者数。)
  • 队列上的
    wait()
    ,在添加或删除队列中的消息后,阻止线程,并
    notifyAll()

这样的设置会自动降低生产者的运行速度,而不是消费者的运行速度。

为什么不实施
阵列锁定队列。

它更好地使用了java.util.concurrent包中的ArrayBlockingQueue类,该类是线程安全的。

BlockingQueue<String> queue = new ArrayBlockingQueue<String>(100);
BlockingQueue=newarrayblockingqueue(100);

这里有一种方法可以完成我想做的事情: