저는 스칼라와 함수 프로그래밍에 비교적 익숙하지 않습니다. 많은 스레드 안전 함정을 피할 수있는 변경 불가능한 객체를 사용한다는 생각을 좋아합니다. 하나의 문제는 여전히 나를 괴롭 히며 스레드 안전성을 가르치는 데 사용되는 고전적인 예인 공유 카운터입니다.스레드 안전 공유 카운터를 구현하는 기능적인 방법
스레드 안전 카운터 (이 예제에서는 요청 카운터)를 구현하고, 변경 불가능한 개체와 기능 개념을 사용하고 동기화를 완전히 피할 수 있는지 궁금합니다.
: 여기에 참조 할 수 있도록 그래서는
변경 가능한, 비 스레드 안전 버전 (단지 예 간결, 대중 멤버 변수 실례) 먼저 카운터 의 고전 변경 가능한 버전입니다
public class Servlet extends HttpServlet { public int requestCount = 0; @Override public void service(ServletRequest req, ServletResponse res) throws ... { requestCount++; //thread unsafe super.service(req, res); } }
변경 가능한, 클래식 스레드 안전 버전 :
public class Servlet extends HttpServlet {
public volatile int requestCount = 0;
@Override
public void service(ServletRequest req, ServletResponse res) throws ... {
synchronized (this) {
requestCount++;
}
super.service(req, res);
}
}
(또는 그래서 ... 희망) 불변 개체 및 휘발성 변수를 사용하여 동기화없이 스레드 안전성을 얻는 방법이 있는지 궁금합니다.
여기 내 순진한 시도였습니다. 아이디어는 카운터에 대해 불변 개체를 갖고, 휘발성 변수를 사용하여 참조를 바꿉니다. 비린내 같지만 한발의 가치가 있습니다.
홀더 :
public class Incrementer {
private final int value;
public Incrementer(final int oldValue) {
this.value = oldValue + 1;
}
public Incrementer() {
this.value = 0;
}
public int getValue() {
return value;
}
}
수정 서블릿 :
public class Servlet extends HttpServlet { public volatile Incrementer incrementer = new Incrementer(); @Override public void service(ServletRequest req, ServletResponse res) throws ... { incrementer = new Incrementer(incrementer.getValue()); super.service(req, res); } }
은 내가 증가 기에서 읽고 있어요으로이 또한 스레드로부터 안전하지 강한 느낌을 가지고 있고, 얻을 수 있습니다 부실 값 (예 : 참조가 이미 다른 스레드로 대체 된 경우) 실제로 스레드가 안전하지 않은 경우 잠금/동기화없이 이러한 카운터 시나리오를 처리 할 수있는 "기능적"방법이 있는지 궁금합니다.
그래서 제 질문 (들)
- 이 스레드는 우연히 안전하다?
- 예인 경우 그 이유는 무엇입니까?
- 그렇지 않은 경우 동기화하지 않고 카운터를 구현할 수있는 방법이 있습니까? 예제 코드는 위의 자바 있지만
, 스칼라 응답도
흥미롭게도 AtomicInteger는 내부적으로 동기화를 사용하기 때문에 답변으로 생각하지도 않았지만 소스 코드를 보면 목표를 달성하는 데 다른 방법 (기본 코드)을 사용하고있는 것처럼 보입니다. http :// /grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/atomic/AtomicInteger.java –