gpt4 book ai didi

java - 多个Java线程中的变量同步

转载 作者:行者123 更新时间:2023-12-02 08:52:21 26 4
gpt4 key购买 nike


我的问题是关于如何使用 block 同步,我的类FileAdapter有一个方法write 接收我用于下载文件的 HTTP 连接结果的 InputStream,每下载和写入 1 KB到磁盘时,它会调用收到的 DownloadReport 类实例的 downloaded 方法,以传递已保存的内容已经下载了。

在另一个向用户打印输出的线程中,它调用了updateProgress方法,该方法也是DownloadReport 类,此方法负责更新在终端上向用户显示的进度条。

问题在于,如果 FileAdapter 类在输出 Thread 尝试时尝试更新下载的字节数更新进度条,因为这两种方法都会编辑变量 intermediateDownloaded 的值,该变量仅作为辅助变量,用于保存自上次更新以来下载的字节数,计算下载速度。

如果我在已下载内使用“同步(此)” block updateProgress方法,它会阻塞整个类DownloadReport,并且输出Thread> 只有在FileAdapter类更新下载字节数后才能更新进度条吗?

文件适配器:

public void write(InputStream content, DownloadReport downloadReport) throws IOException {

FileOutputStream output = new FileOutputStream(file);

byte[] buffer = new byte[1024];

int read;

while ((read = content.read(buffer)) != -1) {
output.write(buffer, 0, read);
downloadReport.downloaded(read);
}
}

下载报告:

public void downloaded(int bytes) {
intermediateDownloaded += bytes;
downloaded += bytes;
}

public void updateProgress() {

long now = System.currentTimeMillis();
double delta = UnitHelper.sizeRound(((now - lastTimeUpdate) / 1000.0), 2);

if (delta >= 1) {
unitAdapter.convertSpeed(intermediateDownloaded, delta);

intermediateDownloaded = 0;
lastTimeUpdate = now;
}

progressBar.updateProgress(unitAdapter.finalSize,
unitAdapter.recalculate(downloaded), unitAdapter.unity);
}

最佳答案

首先,这种类型的同步在最近十年或更长时间里已经失宠,因为:

  • 要做好这件事非常困难
  • 性能受到影响(由于等待)
  • 无法测试。

使用这种方法,您的代码中可能始终存在错误,可能会导致竞争条件,而您不会知道,并且您无法编写单元测试来确保您的代码不受竞争条件的影响。线程之间通信的现代方法是使用消息队列传递不可变消息。

现在,如果您坚持这样做,synchronize( this ) 是一个坏主意,因为任何持有对您对象的引用的人也可以执行 synchronized( yourObject ) code> 然后你就陷入了僵局。对于 synchronized 方法也是如此,因为编译器在底层使用 synchronized( this ) 来实现它们。所以,也不要这样做。始终声明一个私有(private)对象用作锁。

此外,正如您似乎已经了解的那样,同步锁需要尽可能少地处于 Activity 状态,以避免阻塞可能也需要获取该锁的其他线程。因此,它需要包装尽可能少的指令。

就您的代码而言,如果我理解正确,您需要执行以下操作:

private final Object lock = new Object();

public void downloaded( int bytes )
{
synchronized( lock )
{
downloaded += bytes;
}
}

然后,每当您访问 downloaded 时,您还必须与 lock 同步进行,并且您需要找到其他一些方法来计算那个奇怪的 intermediateDownloaded 你的变量仅基于downloaded,因此不需要参与同步。

或者,您可以将 long Download 替换为 java.util.concurrent.atomic.AtomicLong Download,这将允许您比 if 更高效地读取和更新它您使用同步。

关于java - 多个Java线程中的变量同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60695138/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com