"안녕하세요, 아미고! 만병통치약이 있습니다. 만병통치약입니다. 이미 살펴보았듯이 제어되지 않은 스레드 전환이 문제입니다."

"스레드가 다음 스레드로 전환할 시기를 스스로 결정할 수 없는 이유는 무엇입니까? 필요한 모든 작업을 수행한 다음 «완료했습니다!»라고 신호를 보내야 합니까?"

"스레드 자체가 전환을 제어하도록 허용하는 것은 훨씬 더 큰 문제가 될 것입니다. 잘못 작성된 코드가 있고 스레드가 CPU를 포기하지 않는다고 가정해 보겠습니다. 과거에는 이것이 작동하는 방식이었습니다. 그리고 그것은 꽤 악몽이었습니다."

"알았어. 그래서 해결책이 뭐야?"

" 다른 스레드를 차단합니다.  이것이 작동하는 방식입니다."

스레드가 공유 개체 및/또는 리소스를 사용하려고 할 때 스레드가 서로 간섭한다는 것이 분명해졌습니다 . 콘솔 출력의 예에서 본 것처럼 하나의 콘솔과 여기에 대한 모든 스레드 출력이 있습니다. 지저분해.

그래서 특별한 객체인 뮤텍스 가 발명되었습니다 . 화장실 문에 «사용 가능 / 점유» 라고 표시된 표지판과 같습니다 . 두 가지 상태가 있습니다: 개체가 사용 가능 하거나 사용 중 입니다 . 이러한 상태를 «잠김» 및 «잠금 해제»라고도 합니다.

스레드가 다른 스레드와 공유하는 개체가 필요할 때 개체와 관련된 뮤텍스를 확인합니다. 뮤텍스가 잠금 해제되면 스레드는 이를 잠그고(«사용됨»으로 표시) 공유 리소스를 사용하기 시작합니다. 스레드가 작업을 완료한 후 뮤텍스가 잠금 해제됩니다(«사용 가능»으로 표시됨).

스레드가 개체를 사용하려고 하고 뮤텍스가 잠긴 경우 스레드는 대기하는 동안 휴면 상태가 됩니다. 뮤텍스가 점유 스레드에 의해 최종적으로 잠금 해제되면 스레드는 즉시 잠그고 실행을 시작합니다. 욕실 도어 사인과의 비유는 완벽합니다.

"그럼 뮤텍스로 작업하려면 어떻게 해야 합니까? 특수 개체를 만들어야 합니까?"

"그것보다 훨씬 간단합니다. Java 제작자는 이 뮤텍스를 Object 클래스에 내장했습니다. 따라서 만들 필요조차 없습니다. 모든 객체의 일부입니다. 작동 방식은 다음과 같습니다."

암호 설명
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
swap 메소드는 name1 및 name2 변수의 값을 교환합니다.

동시에 두 스레드에서 호출되면 어떻게 될까요?

실제 코드 실행 첫 번째 스레드의 코드 두 번째 스레드의 코드
String s1 = name1; //Ally
name1 = name2; //Lena
name2 = s1; //Ally

String s2 = name1; //Lena
name1 = name2; //Ally
name2 = s2; //Lena
String s1 = name1;
name1 = name2;
//other thread is running
name2 = s1;
//the thread waits until the mutex is unlocked

String s2 = name1;
name1 = name2;
//other thread is running
//other thread is running
name2 = s2;
결론
변수 값이 두 번 바뀌어 원래 위치로 돌아갔습니다.

동기화된 키워드에 주의하십시오  .

"그래, 그게 무슨 뜻이야?"

"스레드가 동기화됨으로 표시된 코드 블록에 들어가면 Java 시스템은 동기화라는 단어 뒤에 괄호 안에 표시된 객체의 뮤텍스를 즉시 잠급니다. 스레드가 떠날 때까지 다른 스레드는 이 블록에 들어갈 수 없습니다. 스레드가 떠나는 즉시 동기화된 것으로 표시된 블록, 뮤텍스는 즉시 자동으로 잠금 해제되며 다른 스레드에서 획득할 수 있습니다."

뮤텍스가 사용 중이면 스레드는 가만히 서서 해제될 때까지 기다립니다.

"매우 간단하고 우아합니다. 아름다운 솔루션입니다."

"예. 하지만 이 경우 어떻게 될 것 같습니까?"

암호 설명
class MyClass
{
private String name1 = "Ally";
private String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}

public void swap2()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}
}
swap 및 swap2 메서드는 동일한 뮤텍스 ( this 개체)를 공유합니다.

한 스레드가 swap 메서드를 호출하고 다른 스레드가 swap2 메서드를 호출하면 어떻게 됩니까?

"뮤텍스가 같기 때문에 두 번째 스레드는 첫 번째 스레드가 동기화된 블록을 떠날 때까지 기다려야 합니다. 따라서 동시 액세스에 문제가 없을 것입니다."

"잘했어, 아미고! 정답이야!"

이제 나는 synchronized가 코드 블록뿐만 아니라 메소드를 표시하는 데 사용될 수 있음을 지적하고 싶습니다 . 이것이 의미하는 바는 다음과 같습니다.

암호 실제로 일어나는 일
class MyClass
{
private static String name1 = "Ally";
private static String name2 = "Lena";

public synchronized void swap()
{
String s = name1;
name1 = name2;
name2 = s;
}

public static synchronized void swap2()
{
String s = name1;
name1 = name2;
name2 = s;
}
}
class MyClass
{
private static String name1 = "Ally";
private static String name2 = "Lena";

public void swap()
{
synchronized (this)
{
String s = name1;
name1 = name2;
name2 = s;
}
}

public static void swap2()
{
synchronized (MyClass.class)
{
String s = name1;
name1 = name2;
name2 = s;
}
}