Как обеспечить правильность результата AtomicLong addAndGet - PullRequest
0 голосов
/ 01 июня 2018

Я хочу рассчитать текущий процент в моей многопоточной программе загрузки. Но есть странная проблема.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 ]

0 голосов
/ 01 июня 2018

Ваша текущая настройка не работает, потому что вы используете 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());
    }
}
0 голосов
/ 01 июня 2018

Ваши 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, потому что синхронизированный блок уже гарантирует, что они толькодоступ к одному потоку одновременно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...