多Java线程中的变量同步

多Java线程中的变量同步,java,multithreading,Java,Multithreading,我的问题是如何使用block synchronized,我的类FileAdapter有一个方法write,它接收我下载文件时使用的HTTP连接结果的InputStream,对于下载并写入磁盘的每千字节,它调用它接收的DownloadReport类实例的下载方法,用于传递已下载的内容。 在另一个向用户打印输出的线程中,它调用updateProgress方法(也是DownloadReport类的方法),该方法负责更新终端上显示给用户的进度条。 问题在于,如果FileAdapter类在输出线程尝试更新

我的问题是如何使用block synchronized,我的类FileAdapter有一个方法write,它接收我下载文件时使用的HTTP连接结果的InputStream,对于下载并写入磁盘的每千字节,它调用它接收的DownloadReport类实例的下载方法,用于传递已下载的内容。 在另一个向用户打印输出的线程中,它调用updateProgress方法(也是DownloadReport类的方法),该方法负责更新终端上显示给用户的进度条。 问题在于,如果FileAdapter类在输出线程尝试更新进度条时尝试更新下载的字节数,因为这两种方法都编辑变量intermediateDownloaded的值,该变量仅作为辅助变量,以保存自上次更新以来下载的字节数,计算下载速度。 如果我在downloaded和updateProgress方法中使用synchronized this块,它将阻止整个类DownloadReport,并且输出线程将只能在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);
}

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

要把它做好是非常困难的 由于等待,它的性能受到影响 这是不稳定的。 使用这种方法,您的代码中可能总是有bug,可能会导致竞争条件,您可能不知道,并且您无法编写单元测试来确保您的代码不受竞争条件的影响。线程间通信的现代方法是使用消息队列传递不可变消息

现在,如果你坚持这样做,同步这是一个坏主意,因为谁持有对你的对象的引用,谁也可以同步你的对象,然后你就死锁了。同步方法也是如此,因为编译器在后台使用同步方法来实现它们。所以,也不要这样做。始终声明要用作锁的私有对象

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

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

private final Object lock = new Object();

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

然后再往下看,无论何时访问下载的文件,都必须与lock同步,并且需要找到其他方法来计算仅基于下载的文件的下载变量,以便它不需要参与同步。

非常感谢您的帮助,但我不明白为什么不在synchronized内部使用它,它会阻止所有具有此类实例的线程吗?@Rafael F N Xavier你应该尝试使用一个私有对象作为同步块的锁,现在,如果您使用公共属性,那么在您的类之外可能有一些代码可以在公共属性上同步,从而导致死锁情况。“this”也是如此,可能有代码超出了类的代码,将同步块放在当前对象上。现在这又会导致deadlock@nits.kk谢谢,读了你的评论,重读了迈克·纳基斯的回答,我现在明白了这个问题。