필요는 다중 스레드 환경에서 AtomicInteger 코드 사용에 문제를 이해하기

이자 :

인터뷰 중 하나에서, 코딩 질문은 나에게 부탁하고 있었고, 난 그 코드에서 문제를 발견하고 적절한 솔루션을 제안했다.

전체 코드를 검색 :

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class Atomic {

    static AtomicInteger count = new AtomicInteger(0);
    static int counter = 0;

    public static class Runnable extends Thread {

    public void run() {
        while (count.getAndSet(1) != 0) {
            try {
                Thread.sleep(3000);
            } catch (Exception e) {

            }
        }
        counter = counter + 1;
        count.set(0);
    }

}

public static void main(String[] args) {
    ExecutorService executor = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 10; i++) {
        Runnable runnable = new Runnable();
        executor.execute(runnable);
    }
    executor.shutdown();
}

}

이 코드는 제대로 실행됩니다. 그러나 문제는,이 스레드의 수가 증가 얻을 경우이 코드에서 일부 문제가되거나 내가 거의 10000 번 루프를 들어 실행하는 경우.

나는 문제를 찾기 위해 노력했지만 하나를 찾을 수 없습니다.

앤디 터너 :

이 코드 문제 몇 가지가 있습니다. 당신은 수단 "몇 가지 문제가있다"로 명시되지했지만, 여기에 뛰어 것들이다.


첫째, counter변수는 안전하게 업데이트되지 않습니다. 다중 스레드가 마지막으로 기록 된 값의 보장 가시성이없는; 도 당신은 다른 스레드가 읽기와 쓰기 사이의 값을 업데이트되지 것을 보장이 없습니다.

이에 대한 간단한 해결책 : 변화 counterAtomicInteger, 사용 getAndIncrement또는 incrementAndGet그것을 증가합니다.


둘째, public static class Runnable extends Thread {이다 매우 모호한.

  1. 일반적으로 알려진 자바 클래스의 이름 (이 숨어 숨기지 마십시오 java.lang.Runnable)
  2. 확장하지 마십시오 Thread당신이 필요로하는 모든이, 특히 직접 java.lang.Runnable으로 실행 추가합니다 ExecutorService.

더 적합한 클래스 선언은 다음과 같습니다

public static class MyRunnable implements Runnable {

(또는 그것을 부르기 위하여 당신이 원한다 무엇 이건)

또는 당신은 익명의 클래스를 선언 할 수 있습니다 :

executor.execute(new Runnable() { /* body */ });

아니면 그냥 람다를 선언 할 수 있습니다 :

executor.execute(() -> { /* body */ });

셋째, count정말 여기 명백한 목적을 제공하지 않는 것. 실행 가능한의 논리는 것 같다 :

  • "플래그가"false 인 경우 :
    1. true로 "플래그"를 설정
    2. 변수를 증가
    3. false로 "플래그"를 설정
  • 그렇지 않으면:
    1. 3 초 기다립니다
    2. 다시 시도하십시오

count여기에 "플래그"의 역할을하고있다. 그것은 효과적으로 그냥 AtomicBoolean.

하지만 당신은 별도의 필요가 없습니다 count당신이 할 경우, 전혀 변수를 counterAtomicInteger:

while (true) {
  int current = counter.get();
  if (counter.compareAndSet(current, current + 1)) {
    // Nothing else is trying to update "current" at the same time:
    // we updated it. Stop.
    break;
  }

  // Something else is trying to update at the same time.
  // Sleep for 3 seconds.
  Thread.sleep(3000);
}

추천

출처http://43.154.161.224:23101/article/api/json?id=14775&siteId=1