JavaRush /Java Blog /Random-KO /스레드 동기화. Java의 동기화 연산자

스레드 동기화. Java의 동기화 연산자

Random-KO 그룹에 게시되었습니다
안녕하세요! 오늘 우리는 계속해서 멀티스레드 프로그래밍의 기능을 고려하고 스레드 동기화에 대해 이야기하겠습니다.
스레드 동기화.  운영자 동기화 - 1
"동기화"란 무엇입니까? 프로그래밍 영역 외부에서는 두 개의 장치나 프로그램이 함께 작동할 수 있도록 하는 일종의 설정을 의미합니다. 예를 들어, 스마트폰과 컴퓨터를 Google 계정과 동기화할 수 있고, 웹사이트의 개인 계정을 소셜 네트워크 계정과 동기화하여 로그인할 수 있습니다. 스레드 동기화도 비슷한 의미를 갖습니다. 스레드가 서로 상호 작용하는 방식을 설정하는 것입니다. 이전 강의에서는 스레드가 서로 별도로 살고 작동했습니다. 한 명은 뭔가를 세고 있었고, 두 번째는 자고 있었고, 세 번째는 콘솔에 뭔가를 표시하고 있었지만 서로 상호작용은 하지 않았습니다. 실제 프로그램에서는 이러한 상황이 거의 발생하지 않습니다. 예를 들어, 여러 스레드가 동일한 데이터 세트를 사용하여 적극적으로 작업하고 그 안에 있는 내용을 변경할 수 있습니다. 이로 인해 문제가 발생합니다. 여러 스레드가 텍스트 파일이나 콘솔과 같은 동일한 위치에 텍스트를 쓰고 있다고 상상해 보십시오. 이 경우 이 파일이나 콘솔은 공유 리소스가 됩니다. 스레드는 서로의 존재를 알지 못하므로 스레드 스케줄러가 할당하는 시간에 관리할 수 있는 모든 것을 간단히 적어 둡니다. 이 과정의 최근 강의에서 이것이 어떤 결과로 이어질지에 대한 예가 있었습니다. 기억해두세요. 스레드 동기화.  동기화 연산자 - 2그 이유는 스레드가 서로 작업을 조정하지 않고 공유 리소스인 콘솔과 함께 작동했다는 사실에 있습니다. 스레드 스케줄러가 Thread-1에 시간을 할당한 경우 모든 것을 즉시 콘솔에 씁니다. 다른 스레드가 이미 작성했거나 작성하지 못한 내용은 중요하지 않습니다. 보시다시피 결과는 비참합니다. 따라서 멀티스레드 프로그래밍에서는 특별한 개념의 뮤텍스가 도입되었습니다(영어 "뮤텍스", "상호 배제" - "상호 배제"에서 유래) . 뮤텍스의 목적은 특정 시간에 하나의 스레드만 개체에 액세스할 수 있도록 메커니즘을 제공하는 것입니다. Thread-1이 개체 A의 뮤텍스를 획득한 경우 다른 스레드는 해당 개체에 액세스하여 그 안의 내용을 변경할 수 없습니다. 객체 A의 뮤텍스가 해제될 때까지 나머지 스레드는 강제로 대기하게 됩니다. 실제 사례: 당신과 다른 10명의 낯선 사람이 훈련에 참여하고 있다고 상상해 보십시오. 번갈아가며 아이디어를 표현하고 토론해야 합니다. 그러나 처음으로 서로를 만나기 때문에 끊임없이 서로를 방해하지 않고 소란에 빠지지 않도록 "말하는 공"규칙을 사용합니다. 단 한 사람 만 말할 수 있습니다. 그의 손. 이렇게 하면 토론이 적절하고 유익한 것으로 판명됩니다. 따라서 뮤텍스는 본질적으로 그러한 공입니다. 개체의 뮤텍스가 한 스레드에 있으면 다른 스레드는 해당 개체에 액세스할 수 없습니다. 뮤텍스를 생성하기 위해 아무것도 할 필요가 없습니다. 뮤텍스는 이미 class 에 내장되어 있으므로 ObjectJava의 모든 객체에 뮤텍스가 있음을 의미합니다.

Java에서 동기화 연산자가 작동하는 방식

새로운 키워드에 대해 알아봅시다 - 동기화 . 이는 우리 코드의 특정 부분을 표시합니다. 코드 블록이 동기화 키워드로 표시되면 해당 블록은 한 번에 하나의 스레드에서만 실행될 수 있음을 의미합니다. 동기화는 다양한 방식으로 구현될 수 있습니다. 예를 들어 전체 동기화 메서드를 만듭니다.
public synchronized void doSomething() {

   //...method logic
}
또는 일부 개체에 대해 동기화가 수행되는 코드 블록을 작성합니다.
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       synchronized (obj) {

           //logic that is only available to one thread at a time
       }
   }
}
의미는 간단합니다. 한 스레드가 동기화라는 단어로 표시된 코드 블록에 들어가면 즉시 개체의 뮤텍스를 획득하고 동일한 블록이나 메서드에 들어가려고 하는 다른 모든 스레드는 이전 스레드가 작업을 완료하고 해당 작업을 해제할 때까지 기다려야 합니다. 감시 장치. 스레드 동기화.  동기화 연산자 - 3그런데! 강의에서 이미 동기화의 예를 보았지만 다르게 보였습니다.
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
이 주제는 새로운 것이므로 처음에는 구문에 혼란이 있을 것입니다. 그러므로 나중에 쓰는 방법이 혼동되지 않도록 즉시 기억하십시오. 이 두 가지 작성 방법은 같은 의미입니다.
public void swap() {

   synchronized (this)
   {
       //...method logic
   }
}


public synchronized void swap() {

   }
}
첫 번째 경우에는 메소드를 입력하자마자 동기화된 코드 블록을 생성합니다. thisobject , 즉 현재 개체에 의해 동기화됩니다 . 두 번째 예에서는 전체 메서드에 동기화라는 단어를 넣었습니다. 더 이상 동기화가 수행되는 개체를 명시적으로 표시할 필요가 없습니다. 전체 메소드가 단어로 표시되면 이 메소드는 클래스의 모든 객체에 대해 자동으로 동기화됩니다. 어떤 방법이 더 나은지에 대한 논의는 다루지 않겠습니다. 지금은 가장 마음에 드는 것을 선택하세요. :) 가장 중요한 점은 메서드 내부의 모든 로직이 동시에 하나의 스레드에 의해 실행될 때만 동기화된 메서드를 선언할 수 있다는 것입니다. 예를 들어, 이 경우 doSomething()메소드를 동기화하면 오류가 발생합니다.
public class Main {

   private Object obj = new Object();

   public void doSomething() {

       //...some logic available to all threads

       synchronized (obj) {

           //logic that is only available to one thread at a time
       }
   }
}
보시다시피 메서드의 일부에는 동기화가 필요하지 않은 논리가 포함되어 있습니다. 그 안에 있는 코드는 여러 스레드에서 동시에 실행될 수 있으며 모든 중요한 위치는 별도의 동기화된 블록에 할당됩니다. 그리고 잠시만요. 이름 교환에 대한 강의의 예를 현미경으로 살펴 보겠습니다.
public void swap()
{
   synchronized (this)
   {
       //...method logic
   }
}
참고: 동기화는 를 사용하여 수행됩니다 this. 즉, 특정 개체에 대한 것입니다 MyClass. Thread-12개의 스레드( 및 Thread-2)와 단 하나의 객체만 있다고 상상해 보세요 MyClass myClass. 이 경우 Thread-1메소드가 호출되면 myClass.swap()객체의 뮤텍스가 사용 중이게 되며 Thread-2호출하려고 하면 myClass.swap()뮤텍스가 해제될 때까지 기다리며 정지됩니다. MyClass2개의 스레드 와 2개의 개체가 myClass1있고 서로 다른 개체에 있는 경우 myClass2스레드는 동기화된 메서드를 동시에 쉽게 실행할 수 있습니다. 첫 번째 스레드는 다음을 수행합니다.
myClass1.swap();
두 번째는 다음을 수행합니다.
myClass2.swap();
이 경우 swap()특정 객체에 대해 동기화가 수행되므로 메소드 내부의 동기화 키워드는 프로그램 작동에 영향을 미치지 않습니다. 후자의 경우에는 2개의 개체가 있으므로 스레드는 서로 문제를 일으키지 않습니다. 결국 두 개체는 서로 다른 뮤텍스를 2개 갖고 있으며 캡처는 서로 의존하지 않습니다.

정적 메서드의 동기화 기능

하지만 정적 메서드를 동기화해야 한다면 어떻게 될까요?
class MyClass {
   private static String name1 = "Olya";
   private static String name2 = "Lena";

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

}
이 경우 뮤텍스 역할을 하는 것이 무엇인지는 확실하지 않습니다. 결국 우리는 이미 모든 객체에 뮤텍스가 있다고 결정했습니다. 하지만 문제는 정적 메서드를 호출하는 데에는 MyClass.swap()개체가 필요하지 않다는 것입니다. 메서드는 정적입니다! 그럼 다음은 무엇입니까? :/ 사실 별 문제는 없습니다. Java 제작자가 모든 것을 처리했습니다. :) 중요한 "멀티스레드" 논리를 포함하는 메서드가 정적이면 동기화는 클래스별로 수행됩니다. 더 명확하게 하기 위해 위 코드를 다음과 같이 다시 작성할 수 있습니다.
class MyClass {
   private static String name1 = "Olya";
   private static String name2 = "Lena";

   public static void swap() {

       synchronized (MyClass.class) {
           String s = name1;
           name1 = name2;
           name2 = s;
       }
   }

}
원칙적으로 이것을 스스로 생각할 수도 있습니다. 객체가 없기 때문에 동기화 메커니즘은 어떻게든 클래스 자체에 "하드와이어"되어야 합니다. 이것이 바로 방법입니다. 클래스 간에 동기화할 수도 있습니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION