Effective Java 버전 3 프로젝트 78 "공유된 가변 데이터에 대한 액세스 동기화"읽기
개시하다
요약
컨텐트
class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested)
i++;
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
backgroundThread
1차 캐시stopRequested
의 값이 계속 false
되기 때문에 순환에서 영원히 벗어날 수 없기 때문이다.해결 방안은 syncronized
수식자를 사용하여 라인 사이를 동기화stopRequested
하는 값이다.class StopThread {
private static boolean stopRequested;
private static synchronized void requestStop() {
stopRequested = true;
}
private static synchronized boolean stopRequested() {
return stopRequested;
}
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested())
i++;
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
requestStop();
}
}
volatile
도 수식자를 사용하여 더욱 간단하게 실현할 수 있다.class StopThread {
private static volatile boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested)
i++;
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
volatile
마운트 필드stopRequested
의 라인이 이 필드에 마지막으로 쓴 값을 가져올 것을 보장합니다.따라서 stopRequested
가 사실이라는 것을 감지할 수 있기 때문에 이 프로그램은 무한순환에 빠지지 않고 처리가 끝난다.volatile
는 마지막 쓰기 필드의 값을 확보하는 것일 뿐 배타 제어를 하는 것이 아니기 때문에 목적에 따라 사용하지 않을 수도 있다.다음 코드가 예다.private static volatile int NEXT_SERIAL_NUMBER = 0;
private static int generateSerialNumber() {
return NEXT_SERIAL_NUMBER++;
}
generateSerialNumber()
방법은 매번 호출될 때마다 독특한 값을 되돌려주지만 실제로는 그렇지 않다.증가 연산자를 사용했기 때문이다.증분 연산자가 읽기NEXT_SERIAL_NUMBER
한 다음 읽은 값을 1로 추가한 후 다시 쓰기NEXT_SERIAL_NUMBER
.위에서 말한 바와 같이 volatile
마지막 쓰기 필드의 값만 가져와서 배타 제어를 하지 않기 때문에 어떤 라인이 NEXT_SERIAL_NUMBER
을 읽고 쓰기 전에 다른 라인이 호출generateSerialNumber()
하면 모든 라인이 같은 값을 얻는다NEXT_SERIAL_NUMBER
설치 의도와 다른 동작이 됩니다.synchronized
수식자를 사용하거나 java.util.concurrent.atomic 포장에 포함된 AtomicLong류를 사용하여 해결할 수 있다.java.util.concurrent.atomic
패키지는 잠금, 스레드 보안 및 원자가 없는 조작을 제공합니다.따라서 synchronized
수식자 동기화 수치를 사용하는 것보다 성능이 좋다.설치 예는 다음과 같습니다.private static final AtomicLong NEXT_SERIAL_NUMBER = new AtomicLong();
public static long generateSerialNumber() {
return NEXT_SERIAL_NUMBER.getAndIncrement();
}
감상
volatile
수식자의 존재를 알았지만 내용만 봐도 사용 상황이 상당히 적다고 느꼈다.다만, 비동기 처리에서 데이터를 공유하고 동시 처리하는 실시 방침이 참고가 되기 때문에 자신이 실시하거나 팀 내에서 논평을 할 때 이 프로젝트의 내용을 떠올려 시스템을 고장내지 마세요.Reference
이 문제에 관하여(Effective Java 버전 3 프로젝트 78 "공유된 가변 데이터에 대한 액세스 동기화"읽기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/empenguin/articles/4318ccb4e760ca텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)