다음 코드는 특정 클래스 메서드를 동기화하는 방법을 보여줍니다.
다음과 같이 코드 코드를 복사합니다.
패키지 신화 읽기;
공개 클래스 SyncThread는 Thread를 확장합니다.
{
개인 정적 문자열 동기화 = "";
개인 문자열 methodType = "";
개인 정적 무효 메소드(문자열 s)
{
동기화 (동기화)
{
동기화 = s;
System.out.println(s);
동안 (사실);
}
}
공개 무효 메소드1()
{
method("방법1");
}
공개 정적 무효 staticMethod1()
{
method("staticMethod1");
}
공개 무효 실행()
{
if (methodType.equals("정적"))
정적메소드1();
else if (methodType.equals("비정적"))
메소드1();
}
공개 SyncThread(문자열 메소드 유형)
{
this.methodType = 메소드 유형;
}
public static void main(String[] args)에서 예외가 발생했습니다.
{
SyncThread 샘플1 = new SyncThread("비정적");
SyncThread 샘플2 = new SyncThread("정적");
샘플1.시작();
샘플2.시작();
}
}
실행 결과는 다음과 같습니다.
다음과 같이 코드 코드를 복사합니다.
방법1
정적 방법1
위의 실행 결과를 보면 많은 독자들이 놀랄 것입니다. 위 코드에서 method1 및 staticMethod1 메서드는 동기화를 위해 정적 문자열 변수 sync를 사용합니다. 이 두 메서드 중 하나만 동시에 실행할 수 있으며 두 메서드 모두 014행의 무한 루프 문을 실행합니다. 따라서 출력 결과는 method1과 staticMethod1 중 하나만 가능합니다. 하지만 이 프로그램은 두 문자열을 모두 출력합니다.
이 결과의 이유는 매우 간단합니다. 012행을 보면 알 수 있습니다. 이 줄에서 sync 값이 변경된 것으로 나타났습니다. 여기서는 Java의 String 유형에 대해 이야기하고 싶습니다. String 유형은 Java의 다른 복합 유형과 다릅니다. String 유형 변수를 사용할 때 변수에 값을 한 번만 할당하면 Java는 String 유형의 새 인스턴스를 생성합니다. 다음 코드에 표시된 대로:
다음과 같이 코드 코드를 복사합니다.
문자열 s = "안녕하세요";
System.out.println(s.hashCode());
s = "세계";
System.out.println(s.hashCode());
위의 코드에서. 첫 번째 s와 재할당된 s의 hashCode 값이 다릅니다. String 클래스의 인스턴스를 생성하는 데는 new를 사용할 필요가 없으므로 String 유형 변수를 동기화할 때 이 변수에 값을 할당하지 않도록 주의하세요. 그렇지 않으면 변수가 동기화되지 않습니다.
line 012에서 sync에 대한 새 인스턴스가 생성되었으므로 method1이 먼저 실행된다고 가정하면 method1이 line 013의 코드를 실행할 때 sync의 값은 더 이상 원래 값이 아니며 method1은 여전히 초기 값을 잠급니다. . 이때 staticMethod1이 동기화(sync)되도록 실행되는데, staticMethod1 메소드에서 잠긴 동기화와 method1 메소드에서 잠긴 동기화가 더 이상 동일하지 않게 됩니다.
위 문제에 대한 해결책은 물론 012행을 제거하는 것입니다. 이 줄은 메서드를 동기화하기 위해 클래스 변수를 사용할 때 동기화된 블록에서 동기화 변수의 값이 변경되면 메서드 간의 동기화가 파괴된다는 점을 설명하기 위해 이 예제에 추가되었습니다. 이러한 상황을 완전히 방지하려면 동기화 변수를 정의할 때 final 키워드를 사용할 수 있습니다. 예를 들어, 위 프로그램의 005행은 다음 형식으로 변경될 수 있습니다.
다음과 같이 코드 코드를 복사합니다.
개인 최종 정적 문자열 동기화 = "";
final 키워드를 사용한 후에는 정의된 경우에만 동기화에서 값을 할당할 수 있으며 나중에 수정할 수 없습니다. 프로그램의 다른 곳에서 sync에 값이 할당되면 프로그램이 컴파일되지 않습니다. Eclipse와 같은 개발 도구에서는 프롬프트가 잘못된 위치에 직접 제공됩니다.
우리는 두 가지 관점에서 동기화된 블록을 이해할 수 있습니다. 클래스 메소드 관점에서 이해하면 해당 메소드는 클래스 변수를 통해 동기화될 수 있다. 클래스 변수의 관점에서 이해한다면 동기화된 블록을 사용하여 동시에 한 메서드에서만 클래스 변수에 액세스할 수 있도록 할 수 있습니다. 어떤 각도에서 이해하든 그 본질은 동일합니다. 즉, 클래스 변수를 사용하여 동기화 잠금을 얻고 동기화 잠금의 상호 배제를 통해 동기화를 달성한다는 것입니다.
참고: 동기화된 블록을 사용할 때 동기화된 블록은 객체만 매개변수로 사용할 수 있다는 점에 유의해야 합니다. 단순한 유형의 변수(예: int, char, boolean 등)인 경우에는 동기화를 위해 동기화를 사용할 수 없습니다.