logo

자바 원자

자바에서는 원자 변수 그리고 운영 동시성에 사용됩니다. 그만큼 멀티스레딩 환경이 문제를 일으킬 때 동시성 통일되어 있습니다. 프로그램이 실행되는 동안 객체, 변수 등 공유 개체가 변경될 수 있습니다. 따라서 프로그램의 불일치로 이어질 수 있습니다. 따라서 동시에 액세스하는 동안 공유 엔터티를 관리하는 것이 중요합니다. 그러한 경우, 원자 변수 그것에 대한 해결책이 될 수 있습니다. 이 섹션에서는 다음 내용을 논의하겠습니다. 원자 클래스, 원자 변수, 원자 연산 , 예시와 함께.

호랑이와 사자의 차이

이 섹션을 계속 진행하기 전에 다음 사항을 알고 있어야 합니다. , 동기화 , 그리고 잠그다 자바에서.

Java 원자 클래스

자바 제공합니다 java.util.concurrent.atomic 원자 클래스가 정의된 패키지입니다. 원자 클래스는 다음을 제공합니다. 잠금이 없는 그리고 스레드로부터 안전한 단일 변수에 대한 환경 또는 프로그래밍. 또한 원자적 작업도 지원합니다. 모든 원자 클래스에는 휘발성 변수에 대해 작동하는 get() 및 set() 메서드가 있습니다. 이 방법은 휘발성 변수에 대한 읽기 및 쓰기와 동일하게 작동합니다.

패키지는 다음 원자 클래스를 제공합니다.

수업 설명
AtomicBoolean 부울 값을 원자적으로 업데이트하는 데 사용됩니다.
원자정수 정수 값을 원자적으로 업데이트하는 데 사용됩니다.
원자정수배열 요소가 원자적으로 업데이트될 수 있는 int 배열입니다.
AtomicIntegerFieldUpdater 지정된 클래스의 지정된 휘발성 int 필드에 대한 원자 업데이트를 가능하게 하는 리플렉션 기반 유틸리티입니다.
AtomicLong 긴 값을 원자적으로 업데이트하는 데 사용됩니다.
AtomicLongArray 요소가 원자적으로 업데이트될 수 있는 긴 배열입니다.
AtomicLongFieldUpdater 지정된 클래스의 지정된 휘발성 긴 필드에 대한 원자 업데이트를 가능하게 하는 리플렉션 기반 유틸리티입니다.
AtomicMarkable참조 AtomicMarkableReference는 원자적으로 업데이트될 수 있는 마크 비트와 함께 객체 참조를 유지합니다.
원자 참조 원자적으로 업데이트될 수 있는 개체 참조입니다.
원자 참조 배열 요소가 원자적으로 업데이트될 수 있는 개체 참조 배열입니다.
AtomicReferenceFieldUpdater 지정된 클래스의 지정된 휘발성 참조 필드에 대한 원자 업데이트를 가능하게 하는 리플렉션 기반 유틸리티입니다.
AtomicStamped참조 AtomicStampedReference는 원자적으로 업데이트될 수 있는 정수 '스탬프'와 함께 객체 참조를 유지합니다.
DoubleAccumulator 제공된 함수를 사용하여 업데이트된 Running Double 값을 함께 유지하는 하나 이상의 변수입니다.
이중가산기 초기에 0의 이중 합을 유지하는 하나 이상의 변수입니다.
LongAccumulator 제공된 함수를 사용하여 업데이트된 Running Long 값을 함께 유지하는 하나 이상의 변수입니다.
장가산기 초기에 0의 장기 합계를 유지하는 하나 이상의 변수입니다.

이 클래스의 객체는 원자 변수를 나타냅니다. int, long, 부울 및 객체 참조 각기. 원자 클래스에는 다음과 같은 몇 가지 일반적인 메서드가 있습니다.

행동 양식 설명
세트() 값을 설정하는데 사용됩니다.
얻다() 현재 값을 가져오는 데 사용됩니다.
게으른 집합() 결국 주어진 값으로 설정됩니다.
비교 및 설정 현재 값 == 예상 값인 경우 값을 지정된 업데이트 값으로 원자적으로 설정합니다.

원자적 연산

항상 함께 실행되는 작업을 원자적 연산 또는 원자 작용 . 효과적으로 실행되는 모든 원자적 작업은 동시에 발생하거나 전혀 발생하지 않습니다. 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 } 

위 코드에서는 스레드 T1이 true로 설정된 후에도 스레드 T2가 절대 멈추지 않을 수 있습니다. 또한 스레드 간에 동기화가 없는 것도 아닙니다.

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에 설정된 순서와 다를 수 있습니다.

Powershell 보다 크거나 같음

예를 통해 이해해 봅시다.

자바를 잡아보세요
 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가 됩니다. 두 개의 개별 스레드로 위 메서드를 호출하면 둘 다 동시에 변수에 액세스하고 값도 업데이트합니다. 동시에 계산합니다. 이러한 상황을 피하기 위해 우리는 원자 연산을 사용합니다.

Java는 다음과 같은 여러 유형의 원자적 작업을 지원합니다.

  • 휘발성 물질 변수
  • 낮은 수준의 원자적 작업(안전하지 않음)
  • 원자 클래스

원자적 연산을 어떻게 생성할 수 있는지 살펴보겠습니다.

원자 변수

원자 변수를 사용하면 변수에 대해 원자 연산을 수행할 수 있습니다. 원자 변수는 동기화를 최소화하고 메모리 일관성 오류를 방지하는 데 도움이 됩니다. 따라서 동기화가 보장됩니다.

Java에서 배열을 초기화하는 방법

원자 패키지는 다음과 같은 5개의 원자 변수를 제공합니다.

  • 원자정수
  • AtomicLong
  • AtomicBoolean
  • 원자정수배열
  • AtomicLongArray

원자변수의 필요성

다음 코드를 고려해 보겠습니다.

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&apos;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&apos;t achieve the same.</td> <td>We can&apos;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&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> <tr> <td>It can lock the same class object or a different class object.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> </table> <hr></max;></pre></max;>

위 프로그램은 단일 스레드 환경에서 실행될 경우 예상되는 출력을 제공합니다. 다중 스레드 환경에서는 예기치 않은 출력이 발생할 수 있습니다. 그 이유는 두 개 이상의 스레드가 동시에 값을 업데이트하려고 하면 제대로 업데이트되지 않을 수 있기 때문입니다.

자바 제안 이 문제를 극복하기 위한 솔루션:

  • 잠금 및 동기화를 사용하여
  • 원자 변수를 사용하여

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&apos;t achieve the same.</td> <td>We can&apos;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&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> <tr> <td>It can lock the same class object or a different class object.</td> <td>We can&apos;t achieve the same.</td> <td>We can&apos;t achieve the same.</td> </tr> </table> <hr></max;>

동기화 대. 원자 대. 휘발성 물질

동기화됨 원자 휘발성 물질
메소드에만 적용됩니다. 변수에만 적용됩니다. 변수에만 적용됩니다.
원자성과 함께 가시성을 보장합니다. 또한 원자성과 함께 가시성을 보장합니다. 원자성이 아닌 가시성을 보장합니다.
우리는 같은 것을 달성할 수 없습니다. 우리는 같은 것을 달성할 수 없습니다. RAM에 저장되므로 휘발성 변수에 대한 액세스가 빠릅니다. 그러나 스레드 안전성과 동기화를 제공하지 않습니다.
동기화된 블록 또는 동기화된 방식으로 구현될 수 있습니다. 우리는 같은 것을 달성할 수 없습니다. 우리는 같은 것을 달성할 수 없습니다.
동일한 클래스 객체를 잠글 수도 있고 다른 클래스 객체를 잠글 수도 있습니다. 우리는 같은 것을 달성할 수 없습니다. 우리는 같은 것을 달성할 수 없습니다.