2015-01-13 3 views
2

나는 초기화에 꽤 시간이 걸리는 클래스가있다; 서버를 호출하고 해당 서버가 준비되는 데 몇 분이 걸립니다.클래스 로딩을 보장하는 방법

해당 클래스의 메소드는 꽤 오래 호출되지 않으며 항상 시작시 자동으로로드되는 클래스에서 호출됩니다. 내 설정은 다음과 같습니다.

class SlowToStartUp { 
    public static void init() { 
    // do nothing 
    } 

    static { 
    initiateConnectionToServer() 
    } 

    public static V invokeServer() { 
    waitForServerToConnect(); 
    return valueFromServer(); 
    } 
} 


class AlwaysLoaded { 
    static { 
    SlowToStartUp.init(); 
    } 

    public void someMethod() { 
    V v = SlowToStartUp.invokeServer(); 
    } 

이것은 구조적으로 정확합니다. init() 함수가 전혀 없으면 처음으로 someMethod() 클래스가 필요하기 전까지 initiateConnectionToServer()이 호출되지 않아 불필요한 (그리고 내 시스템에서 용인 할 수없는) 지연이 발생합니다.

initiateConnectionToServer() 전화를 init()에 넣으면 전화가 끊길 수 있으므로 인터페이스가 더 약해집니다.

그러나 지금 나는 자신보다 현명하지 못한가 궁금합니다. 컴파일러에서 init()이 비어 있음을 알 수 있습니다. 전화를 최적화 할 수는 없습니까? 지금은 그렇게하지 않지만 보장은 있습니까?

init()volatile으로 표시하려고 시도했지만 허용되지 않습니다.

실제 초기화를 init()에 넣고, 멱등수인지 확인하고, 정적 블록에서 호출하여 안전면을 확보하는 것을 고려하고 있지만, 먼저 조언을 요청할 것이라고 생각했습니다.

+0

클래스 생성자에서 초기화를 수행하지 않아도되고 간단하게 클래스가 필요하게 될 때까지 인스턴스 생성을 지연시킬 수 있습니까? 이렇게하면 정적 init() 클래스를 호출하는 것을 잊지 않아도되지만 클래스에서 빠른 응답이 필요한 경우 문제가됩니다. – Brian

+0

그게 전부입니다. 이 프로그램은 금요일 자정에 시작됩니다. 월요일 아침에 사람이 사용합니다. 나는 연결이 이루어지는 동안 그녀가 2 분을 기다려야하는 것을 원하지 않는다. – Malvolio

+2

프로그램을 처음 시작하면 개체를 인스턴스화하는 것이 가능합니까? 아무도 그것을 얼마 동안 필요로하지 않는다고 보장 할 수 있다면, 생성자를 호출하기 전에 메인 클래스 로딩이 끝날 때까지 기다릴 수 있습니다. – Brian

답변

0

나는 내 자신의 질문에 대한 답변이 부족합니다. 클래스 초기화를 트리거하는 이벤트는 JLS 12.4.1에 지정됩니다.

클래스 또는 인터페이스 타입 T

는 다음 중 어느 하나의 제 발생 직전 초기화한다 :

  • T는 T 클래스의 인스턴스가 생성된다.
  • T는 클래스이고 이고 T로 선언 된 정적 메서드는입니다.
  • T로 선언 된 정적 필드가 할당됩니다.
  • T로 선언 된 정적 필드가 사용되며 필드는 상수 변수가 아닙니다 (4.12.4).
  • T는 최상위 클래스이며 T 내에 어휘 적으로 중첩 된 어설 션문 (§14.10)이 실행됩니다.

는 빈 정적 기능을 멀리 최적화 된 컴파일러는 내가 굵은 글씨로 표시 규정을 위반하는 것이라고 나에게 보인다.

댓글 환영합니다.

+0

정적 초기화 프로그램은 정적 메서드와 다릅니다. 정적 이니셜 라이저는 클래스 자체가 초기화되는 것과 동일한 조건에서 트리거되지만, 거기에 아무 것도 없으면 유지할 이유가 없습니다. 마찬가지로 정적 init() 메서드가 비어 있고 호출되지 않으면 컴파일러를 제거 할 이유가 없지만 컴파일러에서 제거해야합니다. – Brian

+0

정적 함수는'init()'을 참조하고있었습니다. 나는 그것을 멀리 낙관하는 것이 명백한 규칙에 위배된다고 생각할 것이다. 나는 지금 당장 사용하는 컴파일러가 그것을 제거하지 않는다고 확신하지만 (잠재적으로) 일시적인 동작에 의존하기를 원하지는 않는다. – Malvolio

+0

비어있는 경우에도 컴파일러가 공용 정적 메서드를 최적화하는 것으로 생각하지 않지만 100 % 확실성으로 말할 수는 없습니다. 특정 경우에, 나는 논점이 논쟁의 여지가 없다 : 생성자에서 클래스를 초기화하고 프로그램 시작시, 일반적으로 또는 싱글 톤으로 새 인스턴스를 생성합니다. 달리해야 할 이유가 있거나 사양에 더 관심이 있습니까? – Brian

3

한 가지 대안은 정적 메서드가 아닌 단일 클래스로 리팩토링하는 것입니다. 그러면 시동시 싱글 톤이 생성되고 초기화 코드가 즉시 실행됩니다.

public class SlowPokeSingleton { 
    private SlowPokeSingleton() { /* execute init code */ } 

    // created at startup 
    private final static SlowPokeSingleton instance = new SlowPokeSingleton(); 

    public static SlowPokeSingleton instance() { return instance; } 
} 

인스턴스가 실제로 생성되었는지 확인하려면 instance()으로 전화해야합니다. 안전을 위해 서버 시작에 추가 할 수 있습니다.

+1

저는 인스턴스가 생성되었는지 확인하기 위해 instance()를 호출해야한다고 100 % 확신합니다. 나는 _days_에 대해 이것을 장난 삼아 해왔다. – Malvolio

0

나는 조반니 보타에 동의 :

당신은 당신의 응용 프로그램이 시작 되 자마자 싱글 인스턴스를 정적 ​​메서드 대신 싱글 톤 패턴을 사용하고 가져올 수 있습니다. 그러면 JVM이 인스턴스를 생성하도록 강제 실행하고 초기화 코드를 실행합니다. - 조반니 보타 특히

는 :

1) 개인 정적 "초기화()"메소드로 초기화의 "시간 낭비"부분을 넣습니다.

2) 클래스의 생성자를 "private"로 만듭니다.

3) 생성자 대신 public static "getInstance()"메서드를 제공하여 (이미 초기화 된) 싱글 톤 인스턴스에 대한 참조를 가져옵니다.

4) 원하는 경우 다른 방법은 비 정적 일 수 있습니다.

관련 문제