Java 1.4 동기화 : 하나의 메소드 인스턴스 만 실행할 수 있습니까 (비 차단)?

StackOverflow https://stackoverflow.com/questions/152138

문제

번역 유틸리티를 제안하는 수업이 있습니다. 번역 자체는 30 분마다 다시로드해야합니다. 나는 그것을 위해 스프링 타이머 지원을 사용합니다. 기본적으로 내 수업은 다음과 같습니다.

public interface Translator {
    public void loadTranslations();
    public String getTranslation(String key);
}

LoadTranslations ()는 실행하는 데 꽤 오래 걸릴 수 있으므로 실행 중에는 이전 번역이 여전히 사용할 수 있습니다. 이것은 로컬 맵에 번역을로드하고 모든 번역이로드 될 때 참조를 변경하여 수행됩니다.

내 문제는 다음과 같습니다. 스레드가 이미로드 된 번역을 할 때 두 번째 스레드가 실행하려고 시도하는 방법은 두 번째 업데이트를 시작하지 않고이를 감지하고 즉시 반환하는지 확인하는 방법입니다.

동기화 된 방법은 하중만을 대기합니다 ... 나는 여전히 Java 1.4에 있으므로 java.util.concurrent가 없습니다.

당신의 도움을 주셔서 감사합니다 !

도움이 되었습니까?

해결책

일부 형태의 잠금 메커니즘을 사용하여 아직 진행중인 경우 만 작업을 수행하십시오. 잠금 토큰을 얻는 것은 1 단계 프로세스 여야합니다. 보다:

/**
 * @author McDowell
 */
public abstract class NonconcurrentTask implements Runnable {

    private boolean token = true;

    private synchronized boolean acquire() {
        boolean ret = token;
        token = false;
        return ret;
    }

    private synchronized void release() {
        token = true;
    }

    public final void run() {
        if (acquire()) {
            try {
                doTask();
            } finally {
                release();
            }
        }
    }

    protected abstract void doTask();

}

작업이 동시에 실행되면 예외를 던지는 테스트 코드 :

public class Test {

    public static void main(String[] args) {
        final NonconcurrentTask shared = new NonconcurrentTask() {
            private boolean working = false;

            protected void doTask() {
                System.out.println("Working: "
                        + Thread.currentThread().getName());
                if (working) {
                    throw new IllegalStateException();
                }
                working = true;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (!working) {
                    throw new IllegalStateException();
                }
                working = false;
            }
        };

        Runnable taskWrapper = new Runnable() {
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    shared.run();
                }
            }
        };
        for (int i = 0; i < 100; i++) {
            new Thread(taskWrapper).start();
        }
    }

}

다른 팁

나는 .NET 배경 (Java 경험이 전혀 없음)에서 왔지만 Alrady가 실행될 때 방법의 시작 부분에서 확인하는 간단한 정적 플래그를 시도 할 수 있습니다. 그러면 해당 플래그의 읽기/쓰기가 동기화되어 있는지 확인하기 만하면됩니다. 따라서 시작시 플래그를 설정하지 않으면 설정이 설정되어 있으면 설정하십시오. 설정되지 않은 경우 방법의 나머지 부분을 실행하고 완료 후에는 설정하지 마십시오. 코드를 시도/마침내 그리고 플래그 iunsetting에 코드를 넣으십시오. 매우 단순화되었지만 필요한 전부 일 수 있습니다.

편집 : 이것은 실제로 방법을 동기화하는 것보다 더 잘 작동 할 것입니다. 당신은 정말로 새로운 번역이 필요하기 때문입니다 즉시 끝나기 전에 하나 후에? 그리고 잠시 기다려야한다면 스레드를 너무 오랫동안 잠그고 싶지 않을 수도 있습니다.

로드 스레드의 손잡이를 유지하여 실행 중인지 확인하십시오.

아니면로드가 진행 중인지 표시하기 위해 동기화 된 플래그를 사용하지 않습니까?

이것은 실제로 고전적인 방식으로 완료되면 싱글 톤 (GASP!)의 구성을 관리하는 데 필요한 코드와 동일합니다.

if (instance == null) {
  synchronized {
    if (instance == null) {
       instance = new SomeClass();
    }
  }
}

내부 테스트는 외부 테스트와 동일합니다. 외부 테스트는 우리가 일상적으로 동기화 된 블록을 입력하지 않도록하기 위해, 내부 테스트는 테스트를 마지막으로 만들었 기 때문에 상황이 변경되지 않았 음을 확인하는 것입니다 (스레드는 동기화되기 전에 스레드가 선점 될 수 있음).

귀하의 경우 :

if (translationsNeedLoading()) {
  synchronized {
    if (translationsNeedLoading()) {
       loadTranslations();
    }
  }
}

업데이트 : 싱글 톤을 구성하는이 방법은 JDK1.4에 따라 안정적으로 작동하지 않습니다. 설명을 위해 여기를 봐. 그러나 나는 당신 이이 시나리오에서 괜찮을 것이라고 생각합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top