当前位置: 首页 > 面试题库 >

2D易失性数组:自我分配会有所帮助还是我需要AtomicIntegerArray?

刘永望
2023-03-14
问题内容

我正在编写一个音频DSP应用程序,并且选择使用生产者-消费者模型。我已经阅读了很多有关volatile线程问题的文章,但是我还遇到了一些有关我的案例的具体问题-
特别是,我需要在线程之间共享的一件事是数组数组。

我有一堂课代表制作人。为了允许处理时间的变化,生产者存储n缓冲区,每当有更多音频数据可用时,生产者都会存储缓冲区,并将缓冲区传递给使用者线程。

我将从问题开始,然后我将尝试详细解释我的系统-冗长的帖子对不起,感谢您的支持!我也非常感谢有关我的实现及其线程安全性的一般性评论。

我的缓冲区由volatile byte[][]数组表示。我很清楚,volatile只有这样才能使 参考
变得不稳定,但是在阅读了SO和各种博客文章之后,看来我有两个选择:

我可以用AtomicIntegerArray。但:

  • 我会为这样的应用程序降低性能吗?

  • 我是否需要原子性?我打算一次性写入整个数组, 然后 需要它对另一个线程可见,而我不需要每个 单独的 写入都立即成为原子的或可见的。

如果我理解正确(例如,本博客文章),则进行自我分配,以我为例:buffers[currentBuffer] = buffers[currentBuffer]将确保发布,您将在下面的代码中看到该自我分配。

  • 这是否正确,它将导致所有最近的写入变为可见?

  • 在像这样的2D阵列的情况下,这行得通吗?

我将简要概述生产者类。这些是实例变量:

// The consumer - just an interface with a process(byte[]) method
AudioInputConsumer consumer;

// The audio data source
AudioSource source;

// The number of buffers
int bufferCount;

// Controls the main producer loop
volatile boolean isRunning = false;

// The actual buffers
volatile byte[][] buffers;

// The number of buffers left to process.
// Shared counter - the producer inrements and checks it has not run
// out of buffers, while the consumer decremenets when it processes a buffer
AtomicInteger buffersToProcess = new AtomicInteger(0);

// The producer thread.
Thread producerThread;

// The consumer thread.
Thread consumerThread;

一旦启动producerThreadconsumerThread,它们便分别执行方法producerLoopconsumerLoop

producerLoop在等待音频数据的同时阻塞数据块,读入缓冲区,对缓冲区 执行自我分配
,然后使用AtomicInteger实例向使用者循环发出信号。

private void producerLoop() {
  int bufferSize = source.getBufferSize();
  int currentBuffer = 0;

  while (isRunning) {
    if (buffersToProcess.get() == bufferCount) {
      //This thread must be faster than the processing thread, we have run out
      // of buffers: decide what to do
      System.err.println("WARNING: run out of buffers");
    }

    source.read(buffers[currentBuffer], 0, bufferSize); // Read data into the buffer
    buffers[currentBuffer] = buffers[currentBuffer];    // Self-assignment to force publication (?)
    buffersToProcess.incrementAndGet();                 // Signal to the other thread that there is data to read
    currentBuffer = (currentBuffer + 1) % bufferCount;  // Next buffer
  }
}

consumerLoop等到AtomicInteger
buffersToProcess大于零,然后调用使用者对象以对数据进行任何处理。之后buffersToProcess递减,我们等待它再次变为非零。

private void consumerLoop() {
  int currentBuffer = 0;

  while (isRunning) {
    if (buffersToProcess.get() > 0) {
      consumer.process(buffers[currentBuffer]);          // Process the data
      buffersToProcess.decrementAndGet();                // Signal that we are done with this buffer
      currentBuffer = (currentBuffer + 1) % bufferCount; // Next buffer
    }
    Thread.yield();
  }
}

非常感谢!


问题答案:

您确实需要原子性,因为写入数组是非原子性的过程。具体来说,Java绝对不会保证对数组成员的写操作对其他线程 不可见 ,除非您选择发布它们。

一种选择是每次创建一个新数组,对其进行完全初始化,然后在上发布volatile,但是由于Java坚持必须首先将新分配的数组先清零,并且由于GC开销,这可能会产生大量成本。您可以使用“双缓冲”方案克服该问题,该方案只保留两个数组并在它们之间切换。这种方法有其危险性:线程可能仍在从您的写入线程已标记为非活动线程的数组中读取数据。这在很大程度上取决于代码的确切细节。

唯一的其他选择是以经典,无聊的代码synchronized块进行整个阅读和写作。这具有延迟可预测的优点。就个人而言,我将从此开始,然后继续进行任何更复杂的事情(如果绝对受实际性能问题的困扰)。

您也可以使用读写锁进行锁定,但是只有在多个线程同时读取数组的情况下,这样做才有意义。这似乎不是您的情况。



 类似资料:
  • 问题内容: 好吧,我可能也已在较早之前发布了此内容,但到目前为止仍找不到答案,因此请帮助我解决这个问题。 我的数据库结构: ATT (表) Act_ID(PK) Assigned_To_ID(FK,请参阅) Project_ID(FK,请参阅) Product_ID(FK,请参阅) 状态(可以是) 产品表 产品编号(PK) 产品名称 项目表 Project_ID(PK) 项目名 员工表 Emp_I

  • /**程序可以将十进制转换为二进制并报告是否使用了非法字符*程序不能将二进制转换为十进制*/import java.util.scanner; /***这个类包含一个完整的程序,只有一个main()方法,用于*将非负十进制整数(即以10为基数的整数)转换为*正二进制整数(即以2为基数的整数)。要*转换的值是从命令行读入的。*/public class BaseConversions2{public

  • 我在尝试为MacBook安装nestJS时遇到了问题,当我使用$npm install-g@nestJS/cli时,这个错误总是在我的终端上弹出。是我做错了什么,还是我没有把这个命令行放在正确的地方?请帮忙:)

  • 我想创建我自己的播客应用程序。 我在网上找到了这段预先编写的代码(),并想对其进行调整,以便创建我自己的应用程序。 如何将此代码上载到expo?

  • 实际上,我正在尝试在2个不同的插件项目中的2个portlet之间共享数据 以下是我分享数据的步骤: 步骤1:创建名为Senderproj的liferay插件项目,并在Senderport下创建一个portlet,然后在doView方法中编写以下代码 Step2:创建名为Receiverproj的增殖插件项目并创建一个名为Receiverport的portlet,然后在doView方法中编写下面的代

  • 我想对我的文件内容进行排序。我的文件内容是学生姓名,他们的学生编号,他们的班级,他们的成绩。这些数据由“;”分隔。首先,我需要计算平均值和字母等级。我已经计算过了,但是我需要将所有内容写入另一个文件,顺序必须是最高等级到最低等级。我该怎么办?