开发者社区> 问答> 正文

多个Java线程中的变量同步

我的问题是关于如何使用同步块的,我的类FileAdapter有一个方法write,它接收用于下载文件的HTTP连接结果的InputStream,对于下载并写入磁盘的每千字节,它调用接收到的DownloadReport类实例的download方法,以传递已下载的内容。 在另一个将输出输出给用户的Thread中,它调用了updateProgress方法,也就是DownloadReport的方法。

类,此方法负责更新在终端上显示给用户的进度条。

这个问题将是,如果FileAdapter类尝试更新的字节数下载只是当输出线程试图更新进度条,因为这两种方法编辑变量的值intermediateDownloaded,它只能作为一个辅助变量,举行自上次更新以来下载的字节数,以计算下载速度。

如果我在downloaded和updateProgress方法中使用“ synchronized(this)”块,它将阻止整个类DownloadReport和输出线程将只能在 FileAdapter类更新下载的字节数之后更新进度条吗?

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

问题来源:Stack Overflow

展开
收起
montos 2020-03-24 12:42:07 560 0
1 条回答
写回答
取消 提交回答
  • 首先,在最近十年或更长时间里,这种类型的同步已不合时宜,因为:

    • 正确地做是非常困难的
    • 它会影响性能(由于等待)
    • 这是不可测的。 使用这种方法,您的代码中总会存在错误,可能会导致竞态条件,并且您不会知道,也没有可以编写的单元测试来确保您的代码不受竞态条件的影响。在线程之间进行通信的现代方法是使用消息队列传递不可变的消息。

    现在,如果您坚持以这种方式进行操作,那将synchronize( this )是一个坏主意,因为拥有对象引用的人也可以这样做synchronized( yourObject ),那么您将陷入僵局。synchronized方法也是如此,因为编译器是在后台使用它们来实现它们synchronized( this )的。因此,也不要这样做。始终声明一个私有对象以用作锁。

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

    对于您的代码,如果我理解正确,则需要执行以下操作:

    private final Object lock = new Object();
    
    public void downloaded( int bytes )
    {
        synchronized( lock )
        {
            downloaded += bytes;
        }
    }
    

    然后在访问时进一步向下移动,downloaded还必须与同步lock,并且您需要找到其他方法来仅intermediateDownloaded基于该方法来计算您的怪异变量downloaded,这样就不必参与同步。

    回答来源:Stack Overflow

    2020-03-24 12:42:57
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud Alibaba - 重新定义 Java Cloud-Native 立即下载
The Reactive Cloud Native Arch 立即下载
多IO线程优化版 立即下载