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();

}
}