2010-02-09 7 views
1

구성 요소를 느리게로드하는 웹 응용 프로그램이 있습니다. 많이 있습니다웹 응용 프로그램의 자바 스레드 동기화

static Bla bla; 
...  
if(bla == null) 
    bla = new Bla(); 

코드 전체에 퍼져 있습니다. 이 스레드가 안전한지 확인하려면 어떻게해야합니까? 내가 synchronized 블록에서 이러한 초기화 중 하나를 수행 할 때마다 그냥 랩해야합니까? 그 일에 어떤 문제가 있습니까?

답변

5

Effective Java [제 2 판, 항목 71, p]에 설명 된 바와 같이 정적 필드에서 지연로드에 가장 적합한 솔루션입니다. 283] 및 Java Concurrency in Practice [p.(348)]를 Initialization on demand holder idiom입니다 :

public class Something { 
    private Something() { 
    } 

    private static class LazyHolder { 
     private static final Something something = new Something(); 
    } 

    public static Something getInstance() { 
     return LazyHolder.something; 
    } 
} 
2

자바 1.5 이상을 사용하는 가정하면,이 작업을 수행 할 수 있습니다 보장

private static volatile Helper helper = null; 

    public static Helper getHelper() { 
     if (helper == null) { 
      synchronized(Helper.class) { 
       if (helper == null) 
        helper = new Helper(); 
      } 
     } 
     return helper; 
    } 

는 쓰레드가 될 수 있습니다.

은 내가 var에 휘발성해야하는 이유를 이해하기 위해이 글을 읽을 것을 권장하고, 널 (null)에 대한 이중 검사가 실제로 필요한 : http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

+1

또한 코드가 JDK5 호환 수준으로 컴파일되도록하거나 휘발성 부분이 파손될 수 있으므로 100 % 확신해야하며 이중 선택 잠금은 의도적으로 중단됩니다. – Romain

+0

감사합니다. 좋은 기사입니다. 내가로드하려고했던 모든 것들이 싱글 톤 이었기 때문에 클래스 HelperSingleton {static Helper singleton = new Helper(); }'패턴을 사용했다. – Kyle

+1

이것은 "이중 확인 잠금"으로 알려져 있으며 원하는 것을 수행하지 않습니다. 예를 들어 여기를 참조하십시오. http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html Ooops는 '휘발성'을 인식하지 못했습니다. 포함하는 클래스의 단일 인스턴스가있는 경우에만 1.5 이상에서 작동합니다. –

1

게으른 인스턴스는 정말 문제의 일부입니다. 이 필드에 액세스하는 것은 어떻습니까?

일반적으로 J2EE 응용 프로그램에서는 가능한 한 이런 종류의 작업을하지 않으므로 코드를 스레딩 문제에서 분리 할 수 ​​있습니다.

아마도 어떤 종류의 전역 상태를 유지하려는 경우 문제를 해결하는 더 좋은 방법이있을 수 있습니다.

귀하의 질문에 직접 대답하기 위해서는 이러한 필드에 대한 액세스가 읽기 및 쓰기 모두 동기화되었는지 확인해야합니다. Java 5는 어떤 경우에는 synchronized를 사용하는 것보다 더 나은 옵션을 가지고 있습니다. 이 문제를 이해하려면 Java Concurrency in Practice을 읽어 보시기 바랍니다.

0

가장 좋은 방법은 같이 동기화 된 블록에 모든 것을 둘러싸, 변수 휘발성를 선언 할 참이다 : 당신이 정말로 하나의 단일 인스턴스는 언제든지 bla에 할당해야하는 경우

private static volatile Bla bla; 
synchronized{ 
    if(bla == null) bla = new Bla(); 
} 

웹 응용 프로그램이 실행중인 경우 static 키워드가 변수 선언에 적용된다는 사실을 염두에 두어 클래스 정의 자 클래스 당 하나의 이 정의되어 있는지 확인해야합니다. BLA는 정적이기 때문에

0

,이 방어하지 않습니다 synchronized{...} 또는 synchronized(this){...} 같은 포함하는 클래스 코드의 다른 인스턴스에서 액세스 할 수 있습니다. 모든 경우에 동일한 객체에 대한 잠금을 가져야합니다. 예를 들어 synchronized(bla){...}

3

가변 변수를 사용하는 것은 까다 롭습니다.

는 여기에 설명 된 것 :

class Singleton 
{ 
    private Vector v; 
    private boolean inUse; 
    private static Singleton instance = new Singleton(); 
    private Singleton() 
    { 
     v = new Vector(); 
     inUse = true; 
     //... 
    } 
    public static Singleton getInstance() 
    { 
     return instance; 
    } 
} 

100 % 작동 훨씬 더 (읽기 및 이해)을 두 번 확인하고 다른 방법에 비해 분명합니다 http://www.ibm.com/developerworks/java/library/j-dcl.html

예는 위의 링크에서 인용 .

+0

이것은 저에게 좋을 것 같습니다. 이렇게하면 어떤 단점이 있습니까? 왜 사람들은 이런 방식으로 할 수만 있다면 이중 잠금 장치를 사용하여 귀찮아 했습니까? – Kyle

+0

@ Spines : 단점은 이것이 게으른 로딩이 아니라는 것입니다. – cherouvim

+0

@cherouvim : 그런 식으로 말하면, 제공 한 기사에서 다음과 같이 말합니다 : Listing 10의 코드는 동기화를 사용하지 않고 static getInstance() 메소드를 호출 할 때까지 Singleton 객체가 생성되지 않도록합니다. – Kyle

0

나는 당신이 게으르게이를로드하는 것이 필요 생각하는 이유를 묻는 것입니다. 웹 앱이라면 이러한 객체가 필요하다는 것을 알고 있습니다. 앱을 시작한 후 열심히로드하고 싶지 않은 이유는 무엇입니까?

지연 성로드가 제공하는 이점을 설명하십시오. 정적 인 경우 이러한 객체를 초기화하지 않을 가능성이 있습니까? 대답이 '아니오'라면 디자인에 도전하고 시작시 열심히로드 할 것을 권장합니다.

+0

안녕하세요 duffymo입니다. 지연되는 이유는 내 앱이 Google App Engine (GAE)에 있기 때문입니다. GAE는 사이트의로드에 따라 앱의 인스턴스를 시작 및 중지하며 사용자가 페이지를 요청할 때 응답을 받기 전에 앱의 모든 초기화가 완료 될 때까지 기다려야 할 가능성이 있습니다. 그래서 내가하는 일은 : 아직 완전히 초기화되지 않은 인스턴스에서 요청이 발생하면 특정 객체를로드하지 않고 캐시에서 페이지를 제공하기 만하면됩니다. – Kyle

+0

느리게로드되는 객체 중 캐시가 있습니까? 그건 GAE의 일부가 아니겠습니까? 귀하의 요점을, 고맙습니다,하지만 init 프로세스의 길이와 다른 사람이 페이지를 요청할 가능성에 대해 궁금합니다. Singleton이 당신을 사겠다는 것은 사용자가 요청할 때 초기화 된 모든 객체를 필요로하지 않을 가능성이 있다는 것입니다. 보증 할 수 없다면이 제도는 도움이되지 않습니다. – duffymo

+0

안녕하세요 Duffymo, 캐시가 지연로드되지 않을 것입니다. 왜냐하면 모든 요청에 ​​상관없이 캐시가 필요하기 때문입니다. 전체 init 프로세스는 약 10 초가 걸리기 때문에 다른 사용자가 init 프로세스 중간에 요청할 가능성이 매우 높습니다. 내 목표는 초기화 프로세스가 완료 될 때까지 캐시에서 계속 서비스하는 것입니다. 느슨하게로드되고 캐시에서 제공된 경우 필요하지 않은 몇 가지 예는 다음과 같습니다. JDO는로드하는 데 약 5 초가 걸리며, 스프링 프레임 워크는 약 2 초가 걸립니다. 지연로드를 통해 사용자는 ~ 10 초가 아닌 ~ 3 초를 기다려야합니다. – Kyle