2015-02-06 2 views
0

우리는 모든 기존 코드를 라이브러리에 패키지화했으며 새로운 코드 버전은 필요한 경우 레거시 코드를 호출합니다. 이 접근법은 좋지만, 현재 레거시 코드의 일부로 스레드 안전하지 않은 싱글 톤이있는 반면, 새로운 코드는 스레드 안전성을 기대합니다. 로드가 특정 숫자를 넘을 때 시스템을 막히게 할 수 있으므로 블록을 동기화 할 여력이 없습니다. 생각은 당신의 의견을 받아 들일 것입니다. 감사!레거시 싱글 톤 깨기

편집 : 이 싱글이 null 인스턴스에서 동기화를 두 번 검사없이 게으른 것들이다 :

public static Parser getInstance() { 
    Parser p = null; 

    try { 
     if (instance == null) { 
      instance = new Parser(...); 
     } 

    } catch (Exception x) { 
     ... 
    } 
    return p; 
} 

이 코드는 우리가 그들을 해결할 수없는, 적어도 8 세입니다.

+1

"스레드가 안전하지 않다"는 것은 무엇을 의미합니까? 이 싱글 톤은 상태 유지입니까? 또는 그들이 구현되는 방식 (둘 이상의 인스턴스를 생성 할 수 있음)과 관련하여 "안전하지 않은"것입니까? 더 자세한 설명과 코드 예제가 없어도 대답하기가 어렵습니다. – alfasin

+0

코드 예제는 모든 사람들이 귀하의 질문을 이해하는 데 도움이됩니다. – Dongqing

+0

'레거시'는 기존 코드입니까? 싱글 톤은 항상 스레드로부터 안전해야하기 때문에 근본적으로 손상된 것처럼 보입니다 (또는 단순히 멀티 스레드 액세스 용으로 설계되지 않은 것 같습니다). 해당 코드를 변경할 수있는 범위가 있습니까? –

답변

0

위의 주석에서 언급했듯이이 클래스를 수정하면됩니다 (쉽게 해결할 수 있습니다!). 즉,이 코드를 만질 수 없다고 가정하면이 코드를 상속하고 "오버라이드"할 수 있습니다 (실제로 메서드가 정적이기 때문에 "숨기기"라고 함) getInstance(). 그러면 깨진 부분 만 수정되고 다른 부분은 같은 논리를 유지하게됩니다.

두번째 null 체크로 싱글 톤을 구현하기로 결정한 경우 가장 안쪽의 체크를 동기화해야 할뿐만 아니라 instancevolatile으로 선언해야합니다.

lazy와 eager 싱글 톤 (정적 클래스, 내부 도우미 클래스 및 열거 형)을 모두 구현하는 더 좋은 방법은 선택하기 전에 모든 옵션을 선택해야합니다.

+0

정적 메소드를 무시할 수 없습니다. 하지만 그는 어쨌든이 모든 것을 다른 클래스에서 구현할 수있을 것입니다. 소스 레벨이나 클래스 파일 레벨에서 원본을 핵으로 만들거나 핵무기를 만들 수 있습니다. – slipperyseal

+0

@ Slippery 당신 말이 맞아요. 숨기는 것입니다. 무시하지 마세요. 그러나 주요 아이디어가 그대로 유지되는 것은 용어 일뿐입니다. – alfasin

+0

아. 시원한. 나는 숨어있는 방법이 일이라는 것을 깨닫지 못했다. iv는 오랫동안 Java를 작성했습니다. :) – slipperyseal

0

스레드 안전하지 않은 객체가 있고 팩토리 메소드가 싱글 톤을 반환하면 동기화 할 수밖에 없습니다.

새 개체를 구성하는 팩토리 메서드를 변경하거나 원래 코드를 편집 할 수없는 경우 새 메서드를 만들어야합니다. 이것이 너무 비싸면 (그리고 그것을 테스트하기 전까지는 가정하지 말아야합니다.) 어떤 측면이 비싸고 객체의 종속성 중 일부가 여전히 싱글 톤일 수 있는지 살펴보십시오.

여기에는 마법의 해결책이 없습니다.

하지만 .. 나는 비슷한 상황에있을 때 한 번 해킹에 대해 이야기하려고합니다. 그러나 이것은 마지막으로 리조트이며 어쨌든 당신의 경우에는 작동하지 않을 수 있습니다. 필자는 전역 변수와 지역 변수를 모두 포함하는 많은 서블릿으로 구성된 웹 응용 프로그램을 구성원 변수로 사용했습니다. 서블릿을 작성한 사람은 서블릿의 구성원이 단일 인스턴스라는 것을 인식하지 못했습니다. 응용 프로그램은 1 개의 클라이언트로 테스트했지만 여러 개의 연결로 실패했습니다. 우리는 빨리 수정해야했습니다. 서블릿을 서면으로 만들자. doGet 및 doPost 메소드가 호출되면 서블릿에서 복제하고 요청을 복제본에 전달합니다. 이것은 "글로벌"멤버를 복사하고 요청에 대해 초기화되지 않은 새로운 멤버를 요청에 보냈습니다. 그러나 문제가 있습니다. 그러지 마라. 방금 코드를 수정하십시오. :)

+0

당신의 평가는 내가 고쳐야 할 것과 매우 가깝습니다. 실제 문제는 특정 '스레드가 안전하지 않은'객체를 캐시하고이를 요청하는 객체를 반환하는 팩토리 클래스에 있습니다. 모든 요청에 ​​대해 새로운 개체를 만들도록 캐시를 비활성화 할 것입니다 (나는 해킹으로 복제하지 않습니다)! –