인터뷰 중 하나에서, 코딩 질문은 나에게 부탁하고 있었고, 난 그 코드에서 문제를 발견하고 적절한 솔루션을 제안했다.
전체 코드를 검색 :
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
변수는 안전하게 업데이트되지 않습니다. 다중 스레드가 마지막으로 기록 된 값의 보장 가시성이없는; 도 당신은 다른 스레드가 읽기와 쓰기 사이의 값을 업데이트되지 것을 보장이 없습니다.
이에 대한 간단한 해결책 : 변화 counter
에 AtomicInteger
, 사용 getAndIncrement
또는 incrementAndGet
그것을 증가합니다.
둘째, public static class Runnable extends Thread {
이다 매우 모호한.
- 일반적으로 알려진 자바 클래스의 이름 (이 숨어 숨기지 마십시오
java.lang.Runnable
) - 확장하지 마십시오
Thread
당신이 필요로하는 모든이, 특히 직접java.lang.Runnable
으로 실행 추가합니다ExecutorService
.
더 적합한 클래스 선언은 다음과 같습니다
public static class MyRunnable implements Runnable {
(또는 그것을 부르기 위하여 당신이 원한다 무엇 이건)
또는 당신은 익명의 클래스를 선언 할 수 있습니다 :
executor.execute(new Runnable() { /* body */ });
아니면 그냥 람다를 선언 할 수 있습니다 :
executor.execute(() -> { /* body */ });
셋째, count
정말 여기 명백한 목적을 제공하지 않는 것. 실행 가능한의 논리는 것 같다 :
- "플래그가"false 인 경우 :
- true로 "플래그"를 설정
- 변수를 증가
- false로 "플래그"를 설정
- 그렇지 않으면:
- 3 초 기다립니다
- 다시 시도하십시오
count
여기에 "플래그"의 역할을하고있다. 그것은 효과적으로 그냥 AtomicBoolean
.
하지만 당신은 별도의 필요가 없습니다 count
당신이 할 경우, 전혀 변수를 counter
를 AtomicInteger
:
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);
}