У Java, атомарні змінні і операції використовується одночасно. The багатопотоковість середовища призводить до проблеми, коли одночасність є уніфікованим. Спільні об’єкти, такі як об’єкти та змінні, можуть бути змінені під час виконання програми. Отже, вони можуть призвести до неузгодженості програми. Отже, важливо подбати про спільну сутність під час одночасного доступу. У таких випадках атомна змінна може бути вирішенням проблеми. У цьому розділі ми обговоримо атомарні класи, атомарні змінні, атомарні операції разом із прикладами.
фон css
Перш ніж рухатися далі в цьому розділі, переконайтеся, що ви знаєте нитка , синхронізація , і замок на Java.
Атомарні класи Java
Java забезпечує a java.util.concurrent.atomic пакет, у якому визначено атомарні класи. Атомні класи забезпечують a без замка і потокобезпечний середовища або програмування на одній змінній. Він також підтримує атомарні операції. Усі атомарні класи мають методи get() і set(), які працюють із змінною volatile. Метод працює так само, як читання та запис мінливих змінних.
Пакет надає наступні атомарні класи:
Клас | опис |
---|---|
AtomicBoolean | Він використовується для атомарного оновлення логічного значення. |
AtomicInteger | Він використовується для атомарного оновлення цілого значення. |
AtomicIntegerArray | Масив int, у якому елементи можна оновлювати атомарно. |
AtomicIntegerFieldUpdater | Утиліта на основі відображення, яка дозволяє атомарно оновлювати призначені volatile int поля визначених класів. |
AtomicLong | Він використовується для атомарного оновлення довгого значення. |
AtomicLongArray | Довгий масив, у якому елементи можна оновлювати атомарно. |
AtomicLongFieldUpdater | Утиліта на основі відображення, яка дає змогу атомарно оновлювати призначені непостійні довгі поля визначених класів. |
AtomicMarkableReference | AtomicMarkableReference підтримує посилання на об’єкт разом із бітом позначки, який можна оновлювати атомарно. |
AtomicReference | Посилання на об’єкт, яке можна оновлювати атомарно. |
AtomicReferenceArray | Масив посилань на об’єкти, у якому елементи можна оновлювати атомарно. |
AtomicReferenceFieldUpdater | Утиліта на основі відображення, яка дає змогу атомарно оновлювати призначені летючі довідкові поля визначених класів. |
AtomicStampedReference | AtomicStampedReference підтримує посилання на об’єкт разом із цілочисельним «штампом», який можна оновлювати атомарно. |
DoubleAccumulator | Одна або кілька змінних, які разом підтримують поточне подвійне значення, оновлене за допомогою наданої функції. |
DoubleAdder | Одна або кілька змінних, які разом зберігають спочатку нульову подвійну суму. |
LongAccumulator | Одна або кілька змінних, які разом підтримують поточне довге значення, оновлене за допомогою наданої функції. |
LongAdder | Одна або більше змінних, які разом підтримують початкову нульову довгу суму. |
Об'єкти цих класів представляють атомарну змінну int, long, boolean , і об'єкт посилання відповідно. Атомарні класи мають такі загальні методи:
методи | опис |
---|---|
набір() | Він використовується для встановлення значення. |
отримати() | Він використовується для отримання поточного значення. |
lazySet() | Зрештою встановлюється задане значення. |
compareAndSet | Атомарно встановлює значення на задане оновлене значення, якщо поточне значення == очікуване значення. |
Атомні операції
Ті операції, які завжди виконуються разом, називаються атомарні операції або атомна дія . Усі атомарні операції, що виконуються ефективно, відбуваються одночасно або не відбуваються взагалі. Три Ключові поняття, пов’язані з атомарними діями в Java, такі:
1. Атомарність має справу з діями та наборами дій невидимий Наприклад, розглянемо такий фрагмент коду:
class NoAtomicOps { long counter=0; void increment() { for(;;) { count++; } } void decrement() { for(;;) { count--; } } //other statement }
У наведеному вище коді поведінка одночасного запуску increment() і decrement() така невизначений і не передбачувано .
2. Видимість визначає, коли може бути ефект однієї нитки бачив іншим. Наприклад, розглянемо такий фрагмент коду:
class InfiniteLoop { boolean done= false; void work() { //thread T2 read while(!done) { //do work } } void stopWork() { //thread T1 write done=true; } //statements }
У наведеному вище коді можливо, що потік T2 ніколи не зупиниться навіть після того, як потік T1 встановить done як true. Крім того, не те, що немає синхронізації між потоками.
3. Порядок визначає, коли дії в одному потоці відбуваються не за порядком по відношенню до іншого.
class Order { boolean a=false; boolean b=false; void demo1() //thread T1 { a=true; b=true; } boolean demo2() //thread T2 { boolean r1=b; //sees true boolean r2=a; //sees false boolean r3=a; //sees true //returns true return (r1 && !r2) && r3; } }
Порядок відображення полів a і b у потоці T2 може відрізнятися від порядку, встановленого в потоці T1.
string.compare c#
Зрозуміємо це на прикладі.
public class AtomicExample { int count; public void incrementCount() { count=1; }
У наведеному вище фрагменті коду ми оголосили змінну типу int рахувати а всередині методу incrementCount() присвоєно йому значення 1. У такому випадку або все станеться разом, або не відбудеться взагалі. Отже, він являє собою атомарна операція і операція відома як атомарність .
Давайте розглянемо ще один фрагмент коду.
public class AtomicExample { int count; public void incrementCount() { count=count+1; }
Здається, що це також атомарна операція, але не так. Це лінійна операція, яка складається з трьох операцій, тобто читання, зміни та запису. Тому він може виконуватися частково. Але якщо ми використовуємо наведений вище код у багатопоточному середовищі, це створює проблему.
Припустімо, ми викликали наведений вище код в однопоточному середовищі, оновлене значення count буде 2. Якщо ми викличемо наведений вище метод двома окремими потоками, вони обидва отримають доступ до змінної одночасно, а також оновлять значення рахувати одночасно. Щоб уникнути цієї ситуації, ми використовуємо атомарну операцію.
точка numpy
Java підтримує кілька типів атомарних дій, а саме:
- Летючі змінні
- Атомарні операції низького рівня (небезпечно)
- Атомні класи
Давайте подивимося, як ми можемо створити атомарну операцію.
Атомна змінна
Атомарна змінна дозволяє нам виконувати атомарну операцію над змінною. Атомарні змінні мінімізують синхронізацію та допомагають уникнути помилок узгодженості пам’яті. Таким чином, це забезпечує синхронізацію.
Пакет atomic надає такі п’ять атомарних змінних:
- AtomicInteger
- AtomicLong
- AtomicBoolean
- AtomicIntegerArray
- AtomicLongArray
Необхідність атомарної змінної
Давайте розглянемо наступний код.
замініть рядок у java
Counter.java
class Counter extends Thread { // Counter Variable int count = 0; //the method starts the execution of a thread public void run() { int max = 1; //increments the counter variable up to specified max time for (int i = 0; i <max; i++) { count++; } public class counter static void main(string args[]) throws interruptedexception creating an instance of the c="new" counter(); four threads thread t1="new" thread(c, 'first'); t2="new" 'second'); t3="new" 'third'); t4="new" 'fourth'); by calling start() method, we have started t1.start(); t2.start(); t3.start(); t4.start(); main will wait for all until execution do not complete t1.join(); t2.join(); t3.join(); t4.join(); prints final value count variable system.out.println(c.count); < pre> <p> <strong>Output:</strong> </p> <pre> 4 </pre> <p>The above program gives the expected output if it is executed in a single-threaded environment. A multi-threaded environment may lead to unexpected output. The reason behind it that when two or more threads try to update the value at the same time then it may not update properly.</p> <p>Java offers <strong>two</strong> solutions to overcome this problem:</p> <ul> <li>By using lock and synchronization</li> <li>By using atomic variable</li> </ul> <p>Let's create a Java program and use an atomic variable to overcome the problem.</p> <h3>By using Atomic Variable</h3> <p> <strong>AtomicExample.java</strong> </p> <pre> class Counter extends Thread { // Counter Variable int count = 0; //the method starts the execution of a thread public void run() { int max = 1; //increments the counter variable up to specified max time for (int i = 0; i <max; i++) { count++; } public class counter static void main(string args[]) throws interruptedexception creating an instance of the c="new" counter(); four threads thread t1="new" thread(c, 'first'); t2="new" 'second'); t3="new" 'third'); t4="new" 'fourth'); by calling start() method, we have started t1.start(); t2.start(); t3.start(); t4.start(); main will wait for all until execution do not complete t1.join(); t2.join(); t3.join(); t4.join(); prints final value count variable system.out.println(c.count); < pre> <p> <strong>Output:</strong> </p> <pre> 4 </pre> <h2>Synchronized Vs. Atomic Vs. Volatile</h2> <table class="table"> <tr> <th>Synchronized</th> <th>Atomic</th> <th>Volatile</th> </tr> <tr> <td>It applies to methods only.</td> <td>It applies to variables only.</td> <td>It also applies to variables only.</td> </tr> <tr> <td>It ensures visibility along with atomicity.</td> <td>It also ensures visibility along with atomicity.</td> <td>It ensures visibility, not atomicity.</td> </tr> <tr> <td>We can't achieve the same.</td> <td>We can't achieve the same.</td> <td>It stores in RAM, so accessing volatile variables is fast. But it does not provide thread-safety and synchronization.</td> </tr> <tr> <td>It can be implemented as a synchronized block or a synchronized method.</td> <td>We can't achieve the same.</td> <td>We can't achieve the same.</td> </tr> <tr> <td>It can lock the same class object or a different class object.</td> <td>We can't achieve the same.</td> <td>We can't achieve the same.</td> </tr> </table> <hr></max;></pre></max;>
Наведена вище програма дає очікуваний вихід, якщо вона виконується в однопоточному середовищі. Багатопотокове середовище може призвести до несподіваного результату. Причина цього полягає в тому, що коли два або більше потоків намагаються оновити значення одночасно, воно може не оновлюватися належним чином.
Пропозиції Java два рішення для подолання цієї проблеми:
- За допомогою блокування та синхронізації
- За допомогою атомної змінної
Давайте створимо програму Java і використаємо атомарну змінну, щоб подолати проблему.
За допомогою атомної змінної
AtomicExample.java
class Counter extends Thread { // Counter Variable int count = 0; //the method starts the execution of a thread public void run() { int max = 1; //increments the counter variable up to specified max time for (int i = 0; i <max; i++) { count++; } public class counter static void main(string args[]) throws interruptedexception creating an instance of the c="new" counter(); four threads thread t1="new" thread(c, \'first\'); t2="new" \'second\'); t3="new" \'third\'); t4="new" \'fourth\'); by calling start() method, we have started t1.start(); t2.start(); t3.start(); t4.start(); main will wait for all until execution do not complete t1.join(); t2.join(); t3.join(); t4.join(); prints final value count variable system.out.println(c.count); < pre> <p> <strong>Output:</strong> </p> <pre> 4 </pre> <h2>Synchronized Vs. Atomic Vs. Volatile</h2> <table class="table"> <tr> <th>Synchronized</th> <th>Atomic</th> <th>Volatile</th> </tr> <tr> <td>It applies to methods only.</td> <td>It applies to variables only.</td> <td>It also applies to variables only.</td> </tr> <tr> <td>It ensures visibility along with atomicity.</td> <td>It also ensures visibility along with atomicity.</td> <td>It ensures visibility, not atomicity.</td> </tr> <tr> <td>We can't achieve the same.</td> <td>We can't achieve the same.</td> <td>It stores in RAM, so accessing volatile variables is fast. But it does not provide thread-safety and synchronization.</td> </tr> <tr> <td>It can be implemented as a synchronized block or a synchronized method.</td> <td>We can't achieve the same.</td> <td>We can't achieve the same.</td> </tr> <tr> <td>It can lock the same class object or a different class object.</td> <td>We can't achieve the same.</td> <td>We can't achieve the same.</td> </tr> </table> <hr></max;>
Синхронізовані Vs. Atomic Vs. Летючі
Синхронізовано | Атомний | Летючі |
---|---|---|
Це стосується лише методів. | Це стосується лише змінних. | Це також стосується лише змінних. |
Це забезпечує видимість разом із атомарністю. | Це також забезпечує видимість разом із атомарністю. | Це забезпечує видимість, а не атомарність. |
Ми не можемо досягти того ж. | Ми не можемо досягти того ж. | Він зберігається в оперативній пам’яті, тому доступ до змінних є швидким. Але це не забезпечує безпеку потоків і синхронізацію. |
Він може бути реалізований як синхронізований блок або синхронізований метод. | Ми не можемо досягти того ж. | Ми не можемо досягти того ж. |
Він може блокувати той самий об’єкт класу або інший об’єкт класу. | Ми не можемо досягти того ж. | Ми не можемо досягти того ж. |