Атомарные переменные в Java с примерами

Опубликовано: 16 Августа, 2021

При многопоточности совместно используемый объект чаще всего приводит к проблеме, когда включен параллелизм. Общая сущность, такая как изменяемый объект или переменная, может быть изменена, что может привести к несогласованности программы или базы данных. Таким образом, становится критически важным иметь дело с разделяемым объектом при одновременном доступе. Атомарная переменная может быть одной из альтернатив в таком сценарии.

Java предоставляет атомарные классы, такие как AtomicInteger, AtomicLong, AtomicBoolean и AtomicReference . Объекты этих классов представляют собой атомарную переменную типа int, long, boolean и ссылку на объект соответственно. Эти классы содержат следующие методы.

  1. set (int value): устанавливает заданное значение
  2. get (): получает текущее значение
  3. lazySet (int value): в конце концов устанавливается на заданное значение
  4. compareAndSet (int expect, int update): атомарно устанавливает значение для данного обновленного значения, если текущее значение == ожидаемое значение
  5. addAndGet (int delta): атомарно добавляет заданное значение к текущему значению.
  6. DecmentAndGet (): атомарно уменьшает на единицу текущее значение

Пример:

// Атомарная переменная
AtomicInteger var;

Потребность в атомарной переменной

Рассмотрим пример ниже:

В однопоточной среде вышеупомянутый класс даст только ожидаемый результат. Но когда речь идет о многопоточной среде, это может привести к противоречивым результатам. Это происходит потому, что обновление «var» выполняется в три этапа: чтение, обновление и запись. Если два или более потока попытаются обновить значение одновременно, оно может не обновиться должным образом.

Эту проблему можно решить с помощью блокировки и синхронизации, но неэффективно.

  1. Использование аналогии с блокировкой или синхронизацией: синхронизация или блокировка могут решить нашу проблему, но это ставит под угрозу эффективность использования времени или производительность. Во-первых, он предписывает планировщику ресурсов и потоков управлять блокировкой. Во-вторых, когда несколько потоков пытаются получить блокировку, только один из них выигрывает, остальные приостанавливаются или блокируются. Приостановка или блокировка потоков может иметь огромное влияние на производительность.




    import java.io.*;
    import java.util.concurrent.locks.*;
    class Counter extends Thread {
    // Counter Variable
    int count = 0 ;
    // method which would be called upon
    // the start of execution of a thread
    public synchronized void run()
    {
    int max = 1_000_00_000;
    // incrementing counter total of max times
    for ( int i = 0 ; i < max; i++) {
    count++;
    }
    }
    }
    public class SynchronizedCounter {
    public static void main(String[] args)
    throws InterruptedException
    {
    // Instance of Counter Class
    Counter c = new Counter();
    // Defining Two different threads
    Thread first = new Thread(c, "First" );
    Thread second = new Thread(c, "Second" );
    // Threads start executing
    first.start();
    second.start();
    // main thread will wait for both
    // threads to complete execution
    first.join();
    second.join();
    // Printing final value of count variable
    System.out.println(c.count);
    }
    }
    Выход:
    200000000
    
  2. Использование атомарной переменной:




    import java.util.concurrent.atomic.AtomicInteger;
    class Counter extends Thread {
    // Atomic counter Variable
    AtomicInteger count;
    // Constructor of class
    Counter()
    {
    count = new AtomicInteger();
    }
    // method which would be called upon
    // the start of execution of a thread
    public void run()
    {
    int max = 1_000_00_000;
    // incrementing counter total of max times
    for ( int i = 0 ; i < max; i++) {
    count.addAndGet( 1 );
    }
    }
    }
    public class AtomicCounter {
    public static void main(String[] args)
    throws InterruptedException
    {
    // Instance of Counter Class
    Counter c = new Counter();
    // Defining Two different threads
    Thread first = new Thread(c, "First" );
    Thread second = new Thread(c, "Second" );
    // Threads start executing
    first.start();
    second.start();
    // main thread will wait for both
    // threads to complete execution
    first.join();
    second.join();
    // Printing final value of count variable
    System.out.println(c.count);
    }
    }
    Выход:
    200000000
    

Вниманию читателя! Не прекращайте учиться сейчас. Ознакомьтесь со всеми важными концепциями Java Foundation и коллекций с помощью курса "Основы Java и Java Collections" по приемлемой для студентов цене и будьте готовы к работе в отрасли. Чтобы завершить подготовку от изучения языка к DS Algo и многому другому, см. Полный курс подготовки к собеседованию .