나는 다음과 같은 몇 가지 클래스가 포함되어있는 내 응용 프로그램에서 일부 잠금 문제로 실행 다음 doSomethingThatWillCallClientGetInstanceSeveralTimes() 메소드에서정적 초기화 및 정적 동기화 방법 잠금 문제
public interface AppClient {
void hello();
}
public class Client implements AppClient {
public synchronized static AppClient getInstance() {
return instance;
}
public void hello() {
System.out.println("Hello Client");
}
private final static class InnerClient implements AppClient {
public void hello() {
System.out.println("Hello InnerClient");
}
}
private static AppClient instance;
static {
instance = new InnerClient();
doSomethingThatWillCallClientGetInstanceSeveralTimes();
}
}
public class Application {
new Thread() {
AppClient c = Client.getInstance();
c.hello();
}.start();
new Thread() {
AppClient c = Client.getInstance();
c.hello();
}.start();
// ...
new Thread() {
AppClient c = Client.getInstance();
c.hello();
}.start();
}
, 꽤 많은 초기화를 할 것입니다 많은 클래스를 포함하는 작업을 초기화하는 동안 Client.getInstance 정적 메서드를 여러 번 순환 호출합니다. 그러나 이것은 좋지 않습니다. 그러나 이것은 20 년 이상 지속되는 레거시 코드 기반입니다. 내가 클래스 클라이언트 초기화, JVM은 Client.class 객체에 동기화하기 때문에 Client.getInstance 방법에 액세스 할 수있는 수준의 클라이언트 초기화를 트리거 첫 번째 스레드를 완료하기 전에 생각
1) : 여기
내 문제입니다 클래스 초기화가 완료되기 전에 관련 주제에 관한 JLS를 읽고이 결론에 도달했습니다 (12.4.2 절, 자세한 초기화 절차, http://java.sun.com/docs/books/jls/third_edition/html/execution.html).2) 그러나 실제 환경에서 보았던 것처럼 행동하지 않았습니다. 예를 들어, Client.getInstance()를 호출하는 세 개의 스레드가 있으며, thread-1은 Client.class 초기화를 트리거하고 doSomethingThatWillCallClientGetInstanceSeveralTimes() 메소드에서 Client.getInstance()를 여러 번 호출합니다. 그리고 doSomethingThatWillCallClientGetInstanceSeveralTimes() 메소드가 완료되기 전에 thread-2는 Client.class 객체의 잠금을 얻습니다 (어떻게 가능합니까?). Client.getInstance 메소드로 들어갑니다 (이 메소드는 정적 동기화 메소드이기 때문에) . 어떤 이유로 Thread-2는 "인스턴스"를 반환 할 수 없습니다 (Client.class가 초기화를 완료하기를 기다리고있는 것 같습니다). 동시에 thread-1은 doSomethingThatWillCallClientGetInstanceSeveralTimes()에서 Client.getInstance를 호출해야하기 때문에 계속 진행할 수 없으며 thread-2가 소유하고 있으므로 잠금을 획득 할 수 없습니다. Threaddump는 thread-2가 RUNNABLE 상태이고 thread-1이 thread-2가 소유 한 잠금을 기다리는 BLOCKED 상태에 있다고 알려줍니다.
Windows의 64 비트 Java 6u23 JVM에서만이 동작을 재현 할 수 있으며 32 비트 Java 6 JVM + Windows 환경을 재현 할 수 없습니다. 누군가 내가 뭘 놓치고 있는지 말해 줄 수 있니? 이러한 종류의 코드가 그러한 잠금을 야기 할 운명에 처해 있습니까? 그렇다면 어떻게해야합니까? 이 부분에 대한 JLS에 대한 이해가 잘못 되었습니까? 아니면 JVM 문제입니까? 어떤 도움을 주셔서 감사합니다. 감사.
코드가 다소 혼란 스럽습니다. 특히 Client와 InnerClient가 AppClient를 구현할 때 특히 그렇습니다. 클라이언트가 필요한 이유를 알 수 없습니다. 문제를 보여주는 짧지만 완전한 * 프로그램을 만들 수 있다면 많은 도움이 될 것입니다. –
@ 존이 문제를 재현하는 간단한 프로그램을 만들 수는 없습니다. 위의 프로그램은 커다란 라이브러리에서 추출한 해골 코드입니다. 문제가 있다고 생각했는데, Client와 InnerClient가 모두 AppClient를 구현하여 역 비교가 가능하기 때문에 중요한 정보를 놓치고 싶지는 않습니다. 이 문제의 원인이되어야합니다. 어쩌면 간단한 프로그램으로이 문제를 보여주기 위해 더 정확한 타이밍과 행운이 필요할 것입니다. 어쨌든 목록에있는 현재 프로그램이 동작 1)처럼 동작 할 것입니다. – nybon
음, 나는 제어 된 방식으로 재생산하는 것에 집중할 것입니다 - 그게 없으면 우리는 정말로 추측 할 수 있기 때문입니다. 당신이 말했듯이, 그것은 * 작동해야만하는 것처럼 들립니다 ... –