Thread.interrupt() 忽略
Thread.interrupt() ignored
我正在尝试编写一种算法来计算声卡输入的音量。虽然这(或多或少)不是问题,但我 运行 在处理多项任务时遇到了麻烦。我从另一个线程调用的中断似乎被忽略了。
我以前开发过多线程环境,我想我知道 Thread.isInterrupted()
与 Thread.interrupted()
和 InterruptedException
的陷阱 - 这就是我专门使用 Thread.isInterrupted()
的原因。 编辑:另外我认为我在这里使用的任何东西都不会抛出 InterruptedException
。
所以我写了这个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!");
}
}
它在初始化时启动输入界面,然后立即自行启动。
class SoundMeter
是外部的 class,它管理 Mixer 使用和初始化 Thread 以及在 Thread 对象上调用中断 (编辑:此class 还接收计算的体积值)。
我认为问题是阻塞 TargetDataLine.read()
方法,但我不确定如何解决这个问题。
Thread.interrupt() 通常只需设置标志即可
If none of the previous conditions hold then this thread's interrupt
status will be set.
所以你的线程将在第一次检查期间结束 while (!isInterrupted()) 在你调用 Thread.interrupt()
在这种情况下,我不使用中断 API,而是使用 boolean
标志 isRunning
,并在线程应该时将其设置为 false
停止。
我们可能无法观察到 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
.
因为 TargetDataLine.read
说它可能会阻塞,所以没有理由期望 isInterrupted()
会在这里工作。
如果 TargetDataLine
在收到 InterruptedException
时再次中断自身为我们设置标志,那就太好了,但没有人说它必须这样做。
我正在尝试编写一种算法来计算声卡输入的音量。虽然这(或多或少)不是问题,但我 运行 在处理多项任务时遇到了麻烦。我从另一个线程调用的中断似乎被忽略了。
我以前开发过多线程环境,我想我知道 Thread.isInterrupted()
与 Thread.interrupted()
和 InterruptedException
的陷阱 - 这就是我专门使用 Thread.isInterrupted()
的原因。 编辑:另外我认为我在这里使用的任何东西都不会抛出 InterruptedException
。
所以我写了这个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!");
}
}
它在初始化时启动输入界面,然后立即自行启动。
class SoundMeter
是外部的 class,它管理 Mixer 使用和初始化 Thread 以及在 Thread 对象上调用中断 (编辑:此class 还接收计算的体积值)。
我认为问题是阻塞 TargetDataLine.read()
方法,但我不确定如何解决这个问题。
Thread.interrupt() 通常只需设置标志即可
If none of the previous conditions hold then this thread's interrupt status will be set.
所以你的线程将在第一次检查期间结束 while (!isInterrupted()) 在你调用 Thread.interrupt()
在这种情况下,我不使用中断 API,而是使用 boolean
标志 isRunning
,并在线程应该时将其设置为 false
停止。
我们可能无法观察到 interrupt()
设置的标志,尤其是当线程阻塞时:
If this thread is blocked in an invocation of the
wait()
,wait(long)
, orwait(long, int)
methods of theObject
class, or of thejoin()
,join(long)
,join(long, int)
,sleep(long)
, orsleep(long, int)
, methods of this class, then its interrupt status will be cleared and it will receive anInterruptedException
.
因为 TargetDataLine.read
说它可能会阻塞,所以没有理由期望 isInterrupted()
会在这里工作。
如果 TargetDataLine
在收到 InterruptedException
时再次中断自身为我们设置标志,那就太好了,但没有人说它必须这样做。