Подтвердить что ты не робот

Java - использование AtomicInteger vs Static int

При использовании нескольких потоков я научился использовать статические переменные всякий раз, когда я хочу использовать счетчик, к которому будут доступны несколько потоков.

Пример:

static int count=0; Затем в программе я использую его как count++;.

Сегодня я наткнулся на то, что называется AtomicInteger, и я также узнал, что он является потокобезопасным и может использовать один из его методов под названием getAndInrement() для достижения такого же эффекта.

Может ли кто-нибудь помочь мне понять, как использовать static atomicInteger versus static int count?

4b9b3361

Ответ 1

- AtomicInteger используется для выполнения атомной операции над целым числом, это альтернатива, когда вы не хотите использовать ключевое слово synchronized.

- Использование volatile в неатомном поле даст несогласованный результат.

int volatile count;

public void inc(){

count++

}

- static создаст переменную , разделяемую всеми экземплярами этого класса, но все же это приведет к несогласованному результату в многопоточной среде.

Итак, попробуйте, когда вы находитесь в многопоточной среде:

1. Всегда лучше следовать правилу Брайана:

Когда мы пишем переменную, которая читается другой нить, или когда мы читаем переменную, которая написана просто другой поток, он должен быть синхронизирован. Общие поля должны быть сделанные частными, делая методы чтения и записи/атомные утверждения синхронизированы.

2. Второй вариант использует Atomic Classes, например AtomicInteger, AtomicLong, AtomicReference, etc.

Ответ 2

Я согласен с ответом @Kumar.

Недостаточно Volatile - это имеет некоторые последствия для порядка памяти, но не обеспечивает атомарность ++.

Действительно сложная задача многопоточного программирования состоит в том, что проблемы могут не проявляться при любом разумном количестве тестирования. Я написал программу для демонстрации проблемы, но у нее есть потоки, которые ничего не делают, кроме приращений. Тем не менее, подсчеты составляют около 1% от правильного ответа. В реальной программе, в которой потоки выполняют другую работу, может быть очень низкая вероятность того, что два потока будут делать ++ достаточно близко, чтобы одновременно показать проблему. Правильность многопоточности не может быть проверена, она должна быть разработана.

Эта программа выполняет ту же задачу подсчета, используя простой статический int, volatile int и AtomicInteger. Только AtomicInteger последовательно получает правильный ответ. Типичный выход на многопроцессорном оборудовании с 4 двухпоточными сердечниками:

count: 1981788 volatileCount: 1982139 atomicCount: 2000000 Expected count: 2000000

Здесь исходный код:

  import java.util.ArrayList;
  import java.util.List;
  import java.util.concurrent.atomic.AtomicInteger;

  public class Test {
    private static int COUNTS_PER_THREAD = 1000000;
    private static int THREADS = 2;

    private static int count = 0;
    private static volatile int volatileCount = 0;
    private static AtomicInteger atomicCount = new AtomicInteger();

    public static void main(String[] args) throws InterruptedException {
      List<Thread> threads = new ArrayList<Thread>(THREADS);
      for (int i = 0; i < THREADS; i++) {
        threads.add(new Thread(new Counter()));
      }
      for (Thread t : threads) {
        t.start();
      }
      for (Thread t : threads) {
        t.join();
      }
      System.out.println("count: " + count +  " volatileCount: " + volatileCount + " atomicCount: "
          + atomicCount + " Expected count: "
          + (THREADS * COUNTS_PER_THREAD));
    }

    private static class Counter implements Runnable {
      @Override
      public void run() {
        for (int i = 0; i < COUNTS_PER_THREAD; i++) {
          count++;
          volatileCount++;
          atomicCount.incrementAndGet();
        }
      }
    }
  }

Ответ 3

С AtomicInteger incrementAndGet() гарантированно будет атомным.
Если вы используете count++, чтобы получить предыдущее значение, он не гарантированно будет атомарным.


Что-то, что я пропустил из вашего вопроса, - и было указано другим ответом - static не имеет ничего общего с потоками.

Ответ 4

"static" делает var равным классу. Это означает, что если вы определите "статический int count" в классе, независимо от того, сколько экземпляров вы создали из класса, все экземпляры используют один и тот же "счет". Хотя AtomicInteger - обычный класс, он просто добавляет защиту синхронизации.

Ответ 5

static int counter даст вам непоследовательный результат в среде multithreaded, если вы не сделаете счетчик volatile или не сделаете блок increment synchronized.

В случае automic он дает программирование lock-free thread-safe для одиночных переменных.

Подробнее в automic и ссылка

Ответ 6

Я думаю, что нет гарантии, чтобы на count++ появилось новое значение. count++ должен прочитать значение count. Другой Thread может записать новое значение в count, но сохранить его значение в локальном кеше Thread, i. е. не сбрасывается в основную память. Также ваш Thread, который читает count, не имеет гарантии для чтения из основной памяти, т.е. е. обновить из основной памяти. synchronize gurantees, которые.

Ответ 7

AtomicInteger должен сделать get и increment как атомный процесс. Его можно рассматривать как секвенсор в базе данных. Он предоставляет методы утилиты для увеличения, уменьшения значений дельта-int.

static int может вызвать проблему, если вы получаете счетчик, а затем обрабатываете, а затем обновляете его. AtomicInteger делает это легко, но вы не можете использовать его, если вам нужно обновить счетчик на основе результатов обработки.