Как обеспечить корректность результата AtomicLong addAndGet
Я хочу рассчитать текущий процент в моей многопоточной программе загрузки. Но есть странная проблема. LastDownloadSize во время второй загрузки должен быть суммой записи и lastDownloadSize для lastDown. пример
Есть мой код
private long getDownloadSize() {
synchronized (this) {
final AtomicLong totalWriteCount = new AtomicLong(0);
final AtomicLong lastDownloadSize = new AtomicLong(0);
for (DownloadTask task : downloadTasks) {
final long writeCount = task.getWriteCount();
totalWriteCount.addAndGet(writeCount);
final long downloadSize = task.getPosition().getDownloadSize();
lastDownloadSize.addAndGet(downloadSize);
}
System.out.println("===== writeCount : " + totalWriteCount + "lastDownloadSize : " + lastDownloadSize);
return totalWriteCount.addAndGet(lastDownloadSize.get());
}
}
2 ответа
Ваш totalWriteCount
а также lastDownloadSize
переменные являются локальными переменными getDownloadSize()
метод. В этом случае не имеет смысла использовать AtomicLong
потому что только один поток может получить к ним доступ.
Что вы, вероятно, имели в виду, это сделать totalWriteCount
а также lastDownloadSize
Члены вашего класса:
class SomeClass {
// ...
final AtomicLong totalWriteCount = new AtomicLong(0);
final AtomicLong lastDownloadSize = new AtomicLong(0);
// ...
private long getDownloadSize() {
synchronized (this) {
for (DownloadTask task : downloadTasks) {
final long writeCount = task.getWriteCount();
totalWriteCount.addAndGet(writeCount);
final long downloadSize = task.getPosition().getDownloadSize();
lastDownloadSize.addAndGet(downloadSize);
}
System.out.println("===== writeCount : " + totalWriteCount + "lastDownloadSize : " + lastDownloadSize);
return totalWriteCount.addAndGet(lastDownloadSize.get());
}
}
}
Тем не менее, также в том случае, если они доступны только изнутри synchronized(this)
блоки, вам не нужно использовать AtomicLong
s, поскольку синхронизированный блок уже обеспечивает одновременный доступ к ним только одного потока.
Ваша текущая настройка не работает, потому что вы используете AtomicLong
неправильный путь. Определение любого Atomic
-класс в одном потоке - просто злоупотребление этим API.
Теперь, почему я сказал один поток, хорошо, что вы синхронизируете, когда кто-то входит в ваш метод, который просто говорит, что только один поток одновременно может использовать этот метод. Что приводит нас к проблеме:
AtomicLong
является локальной переменной
Вы, вероятно, хотели определить свой downloadSize
а также totalWriteCount
как член вашего class
, Например:
public class YourClass {
private final AtomicLong totalWriteCount = new AtomicLong(0);
private final AtomicLong downloadSize = new AtomicLong(0);
/* constructors and other methods */
private synchronized long getDownloadSize() {
for (DownloadTask task : downloadTasks) {
final long writeCount = task.getWriteCount();
totalWriteCount.addAndGet(writeCount);
final long downloadSize = task.getPosition().getDownloadSize();
lastDownloadSize.addAndGet(downloadSize);
}
System.out.println("===== writeCount : " + totalWriteCount + "lastDownloadSize : " + lastDownloadSize);
return totalWriteCount.addAndGet(lastDownloadSize.get());
}
}