Java 调用wait()会使变量i';我刚写信
我正在编写一个合成器应用程序,它有两个振荡器,每个振荡器在自己的线程中运行。我要做的是混合这两个振荡器的信号。当振荡器填充缓冲区时,它通过调用其同步方法Java 调用wait()会使变量i';我刚写信,java,multithreading,concurrency,Java,Multithreading,Concurrency,我正在编写一个合成器应用程序,它有两个振荡器,每个振荡器在自己的线程中运行。我要做的是混合这两个振荡器的信号。当振荡器填充缓冲区时,它通过调用其同步方法sendBuffer()将其传递给SynthMixer对象 package-mixer\u测试; 公共类合成器{ Synth-Synth; 双[]缓冲区1,缓冲区2; 布尔缓冲处理; 公共合成混频器(Synth Synth){ buffer1=null; buffer2=null; this.synth=synth; } 公共同步的void se
sendBuffer()
将其传递给SynthMixer
对象
package-mixer\u测试;
公共类合成器{
Synth-Synth;
双[]缓冲区1,缓冲区2;
布尔缓冲处理;
公共合成混频器(Synth Synth){
buffer1=null;
buffer2=null;
this.synth=synth;
}
公共同步的void sendBuffer(双[]缓冲区){
if(buffer1==null){
buffersProcessed=false;
buffer1=新的双精度[Synth.bufferSize];
for(int i=0;i
编写此代码时,我的想法如下:
其中一个振荡器让线程A上运行的Osc A完成填充缓冲区并调用sendBuffer()
。线程A持有SynthMixer
对象锁,因此即使线程B上的振荡器完成渲染缓冲区,它也会在调用sendBuffer()
之前等待,直到释放锁。因此,线程名为sendBuffer()
,buffer1字段为空,因此if语句执行将传递的缓冲区写入该字段的操作。然后线程A等待释放锁,因此线程B可以调用该方法。现在buffer1不再为null,所以我们正在将振荡器B传递的缓冲区写入buffer2字段mixAndPass()。在这之后,notify()
唤醒线程A,并为下一个缓冲区重复该过程
但结果是,只有通过的信号才是最后启动线程的振荡器的信号。在调试代码时,我可以看到当调用wait()
时,buffer1的值突然变为null。我不明白为什么会发生这种情况,如果能就如何使其正常工作给出解释和建议,我将不胜感激。我对这个问题投反对票,并投票结束,因为不可能在本地重现这种行为。OP没有提供最小的示例,模块
和Synth
类是未知的。我们只能猜测那里发生了什么,但没有人能够完全理解并给出有用的答案。在这些问题内容的问题无法解决之前,我的投票结果将是-1或者问题可能是创建了两个SynthMixer
实例-谁知道呢?检查触发另一个线程调用notify或notifyAll的条件。注意,循环应该在try/catch内部;try/catch不应该在循环中。究竟是什么秘密wait()
释放锁,这允许另一个线程进入您拥有的任何其他同步方法,其中一个方法会将变量置零。我相信问题出在其他地方。调用wait()
后,将buffer1
设置为null
是预期的行为-这正是调用notify()
前的else部分中的另一个线程所做的。您的问题是,最终osc1和osc2都会调用WaveShape.SINE.setFrequency(frequency)代码>最后一个赢了。
package mixer_test;
public class SynthMixer {
Synth synth;
double[] buffer1, buffer2;
boolean buffersProcessed;
public SynthMixer(Synth synth){
buffer1 = null;
buffer2 = null;
this.synth = synth;
}
public synchronized void sendBuffer(double[] buffer) {
if (buffer1 == null) {
buffersProcessed = false;
buffer1 = new double[Synth.bufferSize];
for (int i = 0; i < Synth.bufferSize; i++) {
buffer1[i] = buffer[i];
}
try {
while(!buffersProcessed) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
buffer2 = buffer;
mixAndPass();
buffer1 = null;
buffer2 = null;
buffersProcessed = true;
notify();
}
}
private void mixAndPass(){
double[] outBuffer = new double[Synth.bufferSize];
for(int i = 0; i < Synth.bufferSize; i++){
outBuffer[i] = (buffer1[i] + buffer2[i])/2;
}
synth.passBuffer(outBuffer);
}
}
package mixer_test;
public class Oscillator {
WaveShape wave;
boolean hold;
SynthMixer mixer;
public Oscillator(WaveShape wave, SynthMixer mixer){
this.wave = wave;
this.mixer = mixer;
hold = true;
}
public void start(int frequency){
wave.setFrequency(frequency);
Thread oscillatorLoop = new Thread(new Runnable(){
public void run(){
int sampleNo = 0;
double[] buffer = new double[Synth.bufferSize];
while(hold){
for(int i = 0; i < Synth.bufferSize; i++){
buffer[i] = wave.getSample(sampleNo + i);
}
mixer.sendBuffer(buffer);
sampleNo += Synth.bufferSize;
}
}
});
oscillatorLoop.start();
}
public void stop(){
hold = false;
}
}
package mixer_test;
public class Synth {
public static final int sampleRate = 44100;
public static final int bitDepth = 16;
public static final int bufferSize = 512;
Oscillator osc1, osc2;
SynthMixer mixer;
Amp amp1; // converts double[] to byte[] and writes to SourceDataLine instance
public Synth(){
mixer = new SynthMixer(this);
osc1 = new Oscillator(WaveShape.SINE, mixer );
osc2 = new Oscillator(WaveShape.SINE, mixer);
amp1 = new Amp();
}
public void passBuffer (double[] buffer){
amp1.sendBuffer(buffer);
}
public void play(){
osc2.start(400);
osc1.start(420);
}
public static void main (String[] args){
Synth synth = new Synth();
synth.play();
}
}