简体   繁体   English

Thread.interrupt()被忽略

[英]Thread.interrupt() ignored

I am trying to write an algorithm which calculates the volume of a soundcard input. 我正在尝试编写一种算法来计算声卡输入的音量。 While this is (more or less) not the problem, I run into trouble while multitasking. 尽管这(或多或少)不是问题,但在执行多任务处理时遇到了麻烦。 The interrupts I call from another Thread seem to be ignored. 我从另一个线程调用的中断似乎被忽略了。

I developed multithreaded environments before and I think I know the pitfalls of Thread.isInterrupted() vs. Thread.interrupted() and the InterruptedException - that's why I use Thread.isInterrupted() exclusively. 我之前开发过多线程环境,我想我知道Thread.isInterrupted()Thread.interrupted()InterruptedException的陷阱-这就是为什么我仅使用Thread.isInterrupted()的原因。 Edit : Also I think nothing I use here throws InterruptedException . 编辑 :另外,我认为我在这里使用的任何东西都不会抛出InterruptedException

So I wrote this class: 所以我写了这个课:

import javax.sound.sampled.*;

public class SoundListener extends Thread {

    /**
     * RMS refresh rate in Hz (1000ms / RESPONSE_TIME)
     */
    private static final int REFRESH_RATE = 40;

    private final SoundMeter SOUNDMETER;
    private final AudioFormat AUDIO_FORMAT;
    private final int BUFFER_SIZE;
    private final boolean IS_24_BITS;
    private final TargetDataLine TARGET_DATA_LINE;

    SoundListener(SoundMeter soundMeter, Mixer mixer, AudioFormat audioFormat) throws LineUnavailableException {
        SOUNDMETER = soundMeter;
        AUDIO_FORMAT = audioFormat;
        BUFFER_SIZE = (int) ((AUDIO_FORMAT.getSampleRate() * AUDIO_FORMAT.getSampleSizeInBits()) / REFRESH_RATE);
        IS_24_BITS = AUDIO_FORMAT.getSampleSizeInBits() == 24;
        TARGET_DATA_LINE = AudioSystem.getTargetDataLine(AUDIO_FORMAT, mixer.getMixerInfo());
        TARGET_DATA_LINE.open(AUDIO_FORMAT);
        TARGET_DATA_LINE.start();

        setName("SoundListener");
        setDaemon(true);
        start();
    }

    @Override
    public void run() {

        System.out.println("Thread " + getName() + " started!");

        while (!isInterrupted()) {

            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = TARGET_DATA_LINE.read(buffer, 0, BUFFER_SIZE);

            if (bytesRead >= 0) {

                int max = 0;
                for (int i = 0; i < bytesRead; ) {

                    byte[] subBuffer = new byte[3];
                    subBuffer[0] = buffer[i++];
                    subBuffer[1] = buffer[i++];

                    if (IS_24_BITS) {
                        subBuffer[2] = buffer[i++];
                    }

                    int currentValue = 0;
                    if (AUDIO_FORMAT.isBigEndian()) {
                        if (IS_24_BITS) {
                            currentValue += subBuffer[0] << 16;
                            currentValue += subBuffer[1] << 8;
                            currentValue += subBuffer[2];
                        } else {
                            currentValue += subBuffer[0] << 8;
                            currentValue += subBuffer[1];
                        }
                    } else {
                        if (IS_24_BITS) {
                            currentValue += subBuffer[2] << 16;
                        }
                        currentValue += subBuffer[0];
                        currentValue += subBuffer[1] << 8;
                    }

                    if (currentValue > max) {
                        max = currentValue;
                    }
                }
                SOUNDMETER.setVolume(max);
            }
        }
        TARGET_DATA_LINE.close();

        System.out.println("Thread " + getName() + " stopped!");
    }
}

It starts the input interface on initialization and then right away starts itself. 它在初始化时启动输入接口,然后立即启动自身。

The class SoundMeter is the external class which manages the Mixer to use and initializes the Thread as well as invoking the interrupt on the Thread object ( Edit : This class also receives calculated volume values). SoundMeter类是外部类,它管理混音器使用和初始化Thread以及调用Thread对象上的中断( 编辑 :此类也接收计算的音量值)。

I think the problem is the blocking TargetDataLine.read() method but I am not sure how to solve this. 我认为问题是阻塞的TargetDataLine.read()方法,但是我不确定如何解决此问题。

Instead of using the interrupt API, I'd just use a boolean flag isRunning in this case, and set it to false when the thread should stop. 在这种情况下,我不使用中断API,而是使用一个boolean标志isRunning ,并在线程停止时将其设置为false

The flag set by interrupt() may not be observable to us, particularly when the thread is blocking: 我们可能无法观察到interrupt()设置的标志,尤其是在线程阻塞时:

If this thread is blocked in an invocation of the wait() , wait(long) , or wait(long, int) methods of the Object class, or of the join() , join(long) , join(long, int) , sleep(long) , or sleep(long, int) , methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException . 如果在调用Object类的wait()wait(long)wait(long, int)方法或join()join(long)join(long, int)方法时阻塞了此线程,此类的sleep(long)sleep(long, int)方法,则其中断状态将被清除,并将收到InterruptedException

Since TargetDataLine.read says it may block, there's no reason to expect that isInterrupted() will work here. 由于TargetDataLine.read说它可能会阻塞,所以没有理由期望isInterrupted()在这里可以工作。

It would be nice if TargetDataLine would interrupt itself again to set the flag for us when it receives an InterruptedException , but there's nothing saying it has to. 如果TargetDataLine收到InterruptedException时再次中断自身以为我们设置标志,那将是很好的选择,但是没有什么要说的。

Thread.interrupt() in common way just set the flag and that's all Thread.interrupt()以常用方式设置标志,仅此而已

If none of the previous conditions hold then this thread's interrupt status will be set. 如果上述条件均不成立,则将设置该线程的中断状态。

So you thread will be ended during the first check while (!isInterrupted()) after your call Thread.interrupt() 因此,在调用Thread.interrupt()之后,线程将在(!isInterrupted())的第一次检查期间结束

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM