我有一个程序可以创建一个线程,该线程从48KHz的声卡中捕获数据并将其写入缓冲区进行收集。线程代码的核心如下..
public void run() {
// Run continously
for (;;) {
// get data from the audio device.
getSample();
}
}
// Read in 2 bytes from the audio source combine them together into a single integer
// then write that into the sound buffer
private void getSample () {
int sample,count,total=0,fsample;
byte buffer[]=new byte[2];
try {
while (total<1) {
count=Line.read(buffer,0,2);
total=total+count;
}
} catch (Exception e) {
String err=e.getMessage();
}
sample=(buffer[0]<<8)+buffer[1];
etc etc etc
}
程序正常工作,但该过程似乎占用了CPU的100%时间。我认为这是因为线程正在等待数据到达Line.Read行。我已经尝试在线程中的各个点插入Thread.yield(),但似乎没有任何区别。
有人可以建议我可以减少此线程占用的CPU时间吗?
感谢您的时间
伊恩
答案 0 :(得分:3)
确保线程阻止输入。
如果线程没有阻塞,则该线程占用100%的CPU时间。阻塞将导致线程进入睡眠状态,直到有一些外部刺激将其唤醒。每当你有一个专门的线程来处理输入时,你需要确保它在那个输入上阻塞,这样就会像这样睡觉,这是为了避免线程在其循环中占用100%的CPU时间。
在这种特定情况下,如果Line
是javax.sound.sampled.TargetDataLine
,那么read()
方法就是您应该阻止的地方。根据API,“此方法将一直阻塞,直到读取了所需的数据量”,但“如果数据行在读取请求的数量之前关闭,停止,排空或刷新,则该方法不再阻塞,但是返回到目前为止读取的字节数。“
所以,有几种可能性。我没有看到您对Line
的定义,因此您可能会在某些未包含的代码中刷新或排空该行。如果你这样做,你应该重构你的解决方案,不要使用这些方法。
另一种可能性是,因为你一次只能读取两个字节,所以你的阅读量不足以导致它被阻止。基本上,总有两个字节可用,因为处理你读取的两个字节需要很长时间,总有两个字节可用。尝试增加缓冲区的大小,一次读取更多像4kb。看看是否会导致循环运行频率降低,并且更频繁地阻塞。
答案 1 :(得分:1)
您需要使用远大于2的读缓冲区。在任何情况下,使用相当大的缓冲区大小几乎总是可取的,但由于某些原因,使用小缓冲区大小时javax.sound效率特别低。我在实现基于Java的VU计时学到了这一点。
答案 2 :(得分:0)
将Thread.sleep(a few ms);
置于无限循环中,或者每隔几毫秒使用java.util.Timer
调用getSample()。