문제

나는 몇 가지 자바 코드를 가져오고 설정하는 세션 속성:

Object obj = session.getAttribute(TEST_ATTR);
if (obj==null) {
  obj = new MyObject();
  session.setAttribute(obj);
}

을 만들기 위해 이 코드에 스레드에 안전하고 싶에 포장 동기화됩니다.하지만 나는 무엇을 사용으로 잠그십니까?그것은 감지기를 사용하여 세션?

synchronized (session) {
  Object obj = session.getAttribute(TEST_ATTR);
  if (obj==null) {
    obj = new MyObject();
    session.setAttribute(obj);
  }
}
도움이 되었습니까?

해결책

일반적으로 통제 할 수없는 자물쇠를 사용하는 것이 눈살을 찌푸립니다. 잠금 장치는 가능한 한 단단히 범위를 띠고 세션이 글로벌 대상이므로 청구서에 맞지 않습니다. 에서 별도의 잠금을 사용하십시오 java.util.concurrent.locks 패키지 및 수업에 범위를 띠십시오.

다른 팁

서블릿의 맥락에서? 서블릿은 여러 프로세스에 배포 될 수 있으므로 항상 동일한 세션 객체를 가질 수는 없습니다. 이에 대한 결론은 서블릿 컨테이너가 동일한 프로세스에서 다른 세션 객체를 제공하기로 결정할 수 있다는 것입니다.

IIRC, Brian Goetz는 세션으로 일을 제대로하는 데 어려움에 관한 흥미로운 기사를 썼습니다.

내 조언 : 가능한 한 세션을 피하고 임의의 객체를 잠그지 마십시오 (다른 목적이없는 잠금 객체를 사용하십시오).

나서 문서를 게시합니다.를 생략할 수 있는 동기화 모두 함께하는 방법과 동일한 방법에는 저자를 사용하여 compare-and-설정지 확인하는 데이터가 정확:

ServletContext ctx = getServletConfig().getServletContext();
AtomicReference<TYPE> holder 
    = (AtomicReference<TYPE>) ctx.getAttribute(TEST_ATTR);
while (true) {
    TYPE oldVal = holder.get();
    TYPE newVal = computeNewVal(oldVal);
    if (holder.compareAndSet(oldVal, newVal))
        break;
} 

홀더입니다.compareAndSet(오래된,새로운)는 false 를 반환하는 경우 다른 스레드를 업데이트 값이"홀더기 때문에"당신이 마지막으로 읽습니다.홀더입니다.compareAndSet(,)가 while(true)루프도록 이 값을 변경 하기 전에 당신은 쓸 수 있었다 그 다음 당신은 기회를 얻을 값을 읽기 위해 다시 다시 시도하고 작성합니다.

http://java.sun.com/javase/6/docs/api/java/util/concurrent/atomic/AtomicReference.html

사양은 이것이 전혀 도움이 될 것이라고 보장하지 않습니다.

synchronized (session) {
  Object obj = session.getAttribute(TEST_ATTR);
  if (obj==null) {
    obj = new MyObject();
    session.setAttribute(obj);
  }
}

(특정 구현에는 효과가있을 수 있지만 모든 컨테이너에서 작동한다는 보장은 없습니다.)

Servlet 2.5 MR6 말한다 :

요청 스레드를 실행하는 다중 서블릿은 동시에 동일한 세션 객체에 활성화 할 수 있습니다. 컨테이너는 세션 속성을 나타내는 내부 데이터 구조의 조작이 SuredSafe 방식으로 수행되도록해야합니다. 개발자는 속성 객체 자체에 대한 스레드 Safe 액세스에 대한 책임이 있습니다. 이렇게하면 HTTPSESSION 객체 내부의 속성 수집이 동시 액세스로부터 보호되어 응용 프로그램이 해당 컬렉션이 손상 될 수있는 기회가 제거됩니다.

기본적으로 사양은 문제가됩니다. 솔루션은 응용 프로그램 설계 및 배포 계획에 맞게 조정되어야합니다. 모든 경우에 효과가있는 문제에 대한 글로벌 솔루션이 있는지 확실하지 않습니다. 그러나 응용 프로그램의 아키텍처 및 응용 프로그램 서버 구성에 대해 더 구체적이라면 더 나은 답변을 얻을 수 있습니다.

코드는 적어도 두 가지 이유로 작동하지 않습니다.

1) 세션이 존재하지 않으면 동일한 사용자를 위해 쉽게 두 번 만들 수 있고 추악한 경주 상태를 가질 수 있습니다.

2) 세션이 스레드에서 동일한 객체가 아닌 경우 어쨌든 작동하지 않습니다. 세션은 아마도있을 것입니다 equals() 다른 스레드에서 같은 세션에 이루어 지지만 작동하지 않습니다.

그 이후로 잠글 필요가 없습니다 session.setAttribute() 스레드 안전합니다 (위의 @mcdowell의 서블릿 사양 주석 참조).

그러나 다른 예를 사용해 봅시다. 속성의 값을 잡고 <= 100 인 경우 업데이트하고 싶다고 가정 해 봅시다.이 경우 코드 블록을 동기화해야합니다. getAttribute() 비교 <= 100 및 the setAttribute().

이제 잠금에 무엇을 사용해야합니까? 잠금에 다른 물체를 사용하는 경우 동기화가 없음을 기억하십시오. 따라서 다른 코드 블록은 동일한 객체를 사용해야합니다. 당신의 선택 session 물체는 괜찮을 수 있습니다. 다른 코드 블록은 다른 코드가 세션 객체에 잠겨 있지 않는 한 잠금을 취한 경우에도 세션 (읽기/쓰기)에 액세스 할 수 있음을 기억하십시오. 여기서 함정은 코드의 너무 많은 장소가 세션 객체를 잠그고 기다려야한다는 것입니다. 예를 들어, 코드 블록이 세션 속성 A와 다른 코드 덩어리를 사용하는 경우 세션 속성 B를 사용하는 경우 세션 객체를 잠금하여 서로 대기 할 필요가 없으면 좋을 것입니다. Lockfora라는 정적 객체를 사용하고 Lockforb는 코드를 사용하는 데 더 나은 선택 일 수 있습니다. synchronized (LockForA) { }.

나는 같은 문제가 있었고 내 객체의 생성이 1 초가 걸리고 객체가 이미 생성 된 다른 세션의 스레드를 스톨을 걸었을 수 있기 때문에 내 수업에 범위를 범하고 싶지 않았습니다. 애플리케이션 서버 구현이 다른 요청에서 다른 세션 외관을 반환하고 다른 객체의 동기화가 작동하지 않기 때문에 요청의 세션 객체를 동기화하기 위해 동기화하기 위해 동기화하고 싶지 않았습니다. 그래서 나는 세션에 객체를 잠금으로 사용할 수 있도록 선택하고 이중 확인 관용구를 사용하여 잠금이 한 번만 생성되도록합니다. MyObject의 범위에서 동기화하는 것은 객체를 만드는 것이 매우 빠르기 때문에 더 이상 문제가되지 않습니다.

Object lock = session.getAttribute("SessionLock");
if (lock == null) {
  synchronized (MyObject.class) {
    lock = session.getAttribute("SessionLock");
    if(lock == null) {
      lock = new Object();
      session.setAttribute("SessionLock", lock);
    }
  }
}
synchronized (lock) {
  Object obj = session.getAttribute(TEST_ATTR);
  if (obj==null) {
    obj = new MyObject();
    session.setAttribute(obj);
  }
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top