Programing

같은 클래스에서 두 메소드를 동기화하면 동시에 실행될 수 있는가?

c10106 2022. 5. 4. 19:03
반응형

같은 클래스에서 두 메소드를 동기화하면 동시에 실행될 수 있는가?

같은 클래스에서 두 메서드를 동기화하면 동일한 개체에서 동시에 실행할 수 있는가?예를 들면 다음과 같다.

class A {
    public synchronized void methodA() {
        //method A
    }

    public synchronized void methodB() {
        // method B
    }
}

나는 내가 달릴 수 없다는 것을 안다.methodA()두 개의 다른 실로 같은 물체에 두 번. 같은 것으로methodB().

하지만 달릴 수 있을까?methodB()와는 다른 실타래로.methodA()아직도 달리고 있니?(대상)

두 방법 모두 동일한 모니터를 잠근다.따라서 서로 다른 스레드의 동일한 개체에서 동시에 실행할 수 없다(두 가지 방법 중 하나는 다른 방법이 완료될 때까지 차단된다).

예제에서 방법 A와 방법 B는 (정적인 방법과는 반대로) 인스턴스 방법이다.놓는 것synchronized인스턴스(instance) 메서드에서 스레드가 해당 메서드의 코드를 실행하기 전에 메서드가 호출되는 객체 인스턴스의 잠금("instance lock")을 스레드가 획득해야 함을 의미한다.

동기화된 것으로 표시된 두 개의 다른 인스턴스 메서드가 있고 다른 스레드가 동일한 개체에서 동시에 이러한 메서드를 호출하는 경우, 해당 스레드는 동일한 잠금을 위해 경쟁하게 될 것이다.한 스레드가 잠기면 다른 스레드는 해당 객체의 모든 동기화된 인스턴스 메서드에서 차단된다.

두 가지 방법을 동시에 실행하려면 다음과 같이 서로 다른 잠금 장치를 사용해야 한다.

class A {
    private final Object lockA = new Object();
    private final Object lockB = new Object();

    public void methodA() {
        synchronized(lockA) {
            //method A
        }
    }

    public void methodB() {
        synchronized(lockB) {
            //method B
        }
    }
}

여기서 동기화된 블록 구문에서는 실행 스레드가 블록에 들어가기 위해 본질적인 잠금을 획득해야 하는 특정 개체를 지정할 수 있다.

이해해야 할 중요한 것은 개별적인 방법에 '동기화' 키워드를 붙이면서도 핵심 개념은 배후에서 내재된 자물쇠라는 점이다.

Java 자습서에서는 다음과 같이 관계를 설명한다.

동기화는 본질적 잠금 또는 모니터 잠금이라고 알려진 내부 실체를 중심으로 구축된다.(API 규격은 종종 이 실체를 단순히 "모니터"라고 부른다.) 내적 잠금들은 동기화의 두 가지 측면 모두에서 역할을 한다: 물체의 상태에 대한 독점적 접근을 시행하고 그에 필수적인 관계를 설정하기 전에 일어난다.가시성

모든 물체는 그것과 연관된 본질적인 자물쇠를 가지고 있다.관례에 따라, 개체의 필드에 대한 배타적이고 일관성 있는 액세스가 필요한 스레드는 접근하기 전에 개체의 내적 잠금을 획득한 다음, 내적 잠금을 해제해야 한다.실이 자물쇠를 획득한 후 잠금을 해제한 시간 사이에 본질적인 자물쇠를 소유한다고 한다.나사산이 본질적인 자물쇠를 소유하는 한, 다른 어떤 나사산도 동일한 자물쇠를 획득할 수 없다.다른 나사산은 잠금을 획득하려고 할 때 차단된다.

잠그는 목적은 공유 데이터를 보호하는 것이다.각 잠금이 서로 다른 데이터 구성원을 보호한 경우에만 위의 예 코드와 같이 별도의 잠금을 사용하십시오.

Java Thread는 인스턴스 동기화된 Java 메서드에 들어갈 때 객체 레벨 잠금을 획득하고 정적 동기화된 Java 메서드에 들어갈 때 클래스 레벨 잠금을 획득한다.

당신의 경우, 그 방법(인스턴스)은 동급이다.따라서 스레드가 Java 동기화된 메서드에 들어가거나 차단되면 잠금(메서드가 호출되는 개체)을 얻는다.따라서 첫 번째 방법이 완성되고 (물체에 대한) 잠금이 해제될 때까지 동일한 물체에 대해 다른 방법을 동시에 호출할 수 없다.

같은 클래스의 동일한 인스턴스에서 두 가지 방법을 동기화하십시오.따라서 이 두 가지 방법은 클래스 A의 동일한 인스턴스의 서로 다른 스레드에서 동시에 실행할 수 없다.그러나 그들은 다른 클래스 A 인스턴스들을 사용할 수 있다.

class A {
    public synchronized void methodA() {
        //method A
    }
}

다음 항목과 동일함:

class A {
    public void methodA() {
        synchronized(this){
            // code of method A
        }
    }
}

코드를 다음과 같이 생각하십시오.

class A {

public void methodA() {
    synchronized(this){        
      //method A body
    }
}

public void methodB() {
    synchronized(this){
      // method B body
    }
}

따라서, 방법 수준에서 동기화된다는 것은 단순히 동기화된다는 것을 의미한다.스레드가 이 클래스의 메서드를 실행하는 경우, 실행을 시작하기 전에 잠금을 얻고 메서드의 실행이 완료될 때까지 잠금을 유지한다.

그러나 메서드A()가 아직 실행 중인 동안 메서드B()를 다른 스레드에서 실행할 수 있는가?(대상)

정말, 그것은 불가능해!

따라서 여러 개의 스레드는 동일한 개체에서 동기화된 메서드를 여러 개 동시에 실행할 수 없을 것이다.

Oracle 설명서 링크에서

동기화된 메서드를 만드는 데는 두 가지 효과가 있다.

첫째, 동일한 객체에서 동기화된 메서드의 두 번의 호출이 상호 이탈하는 것은 불가능하다.한 스레드가 개체에 대해 동기화된 메서드를 실행할 때 첫 번째 스레드가 개체와 함께 수행될 때까지 동일한 개체 블록에 대해 동기화된 메서드를 호출하는 다른 모든 스레드(실행 중지)

둘째, 동기화된 방법이 종료되면, 그것은 자동으로 동일한 개체에 대해 동기화된 방법의 후속 호출과 함께 발생 전 관계를 설정한다.이렇게 하면 모든 스레드에 개체의 상태 변경이 표시됨

이렇게 하면 다음과 같은 질문에 답할 수 있다.동일한 개체에서 첫 번째 동기화된 메서드 실행이 진행 중일 때는 두 번째 동기화된 메서드를 호출할 수 없다.

본질적인 잠금 및 잠금 동작을 이해하려면 이 문서 페이지를 살펴보십시오.

확실히, 정적 동기화된 방법과 비 정적 동기화된 방법이 동시에 또는 동시에 실행될 수 있는 것은 한 방법이 물체 수준 잠금과 다른 클래스 수준 잠금을 가지고 있기 때문이다.

쉽게 가라앉지 않는 동기화의 핵심 아이디어는 동일한 개체 인스턴스에 대해 방법을 호출해야 효과가 있다는 것이다. 즉, 답변과 논평에서 이미 강조되어 있다.

아래 샘플 프로그램은 동일한 항목을 명확하게 가리키는 것이다.

public class Test {

public synchronized void methodA(String currentObjectName) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodA out");
}

public synchronized void methodB(String currentObjectName)  throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB in");
    Thread.sleep(1000);
    System.out.println(Thread.currentThread().getName() + "->" +currentObjectName + "->methodB out");
}

public static void main(String[] args){
    Test object1 = new Test();
    Test object2 = new Test();
    //passing object instances to the runnable to make calls later
    TestRunner runner = new TestRunner(object1,object2);
    // you need to start atleast two threads to properly see the behaviour
    Thread thread1 = new Thread(runner);
    thread1.start();
    Thread thread2 = new Thread(runner);
    thread2.start();
}
}

class TestRunner implements Runnable {
Test object1;
Test object2;

public TestRunner(Test h1,Test h2) {
    this.object1 = h1;
    this.object2 = h2;
}

@Override
public void run() {
    synchronizedEffectiveAsMethodsCalledOnSameObject(object1);
    //noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(object1,object2);
}

// this method calls the method A and B with same object instance object1 hence simultaneous NOT possible
private void synchronizedEffectiveAsMethodsCalledOnSameObject(Test object1) {
    try {
        object1.methodA("object1");
        object1.methodB("object1");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

// this method calls the method A and B with different object instances object1 and object2 hence simultaneous IS possible
private void noEffectOfSynchronizedAsMethodsCalledOnDifferentObjects(Test object1,Test object2) {
    try {
        object1.methodA("object1");
        object2.methodB("object2");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
}

다른 개체 인스턴스에서 메서드를 호출할 경우 예상대로 동시 액세스가 허용되는 방법의 출력 차이를 주목하십시오.

Ouput with noEffectOfSynchronizedAsMethods CallingOnDifferentObjects() comment -출력은 methods in > methods A in methodes A in > methods A in methods ..method B Out.

동기화된 EffectiveAs를 사용한 OuputMethodsOnSameObject() 코멘트 - 출력은 강조 표시된 섹션의 Thread1 및 Thread0에 의한 메서드A 동시 액세스를 보여준다.

*동기화된 EffectiveAs를 사용한 Ouput

실 수를 늘리면 더욱 눈에 띄게 된다.

아니, 가능하지 않다면 두 방법이 동시에 동일한 변수를 업데이트하여 데이터를 쉽게 손상시킬 수 있다.

클래스가 아닌 오브젝트에서 동기화하는 중.그래서 그들은 같은 물체에서 동시에 달릴 수 없다.

네, 두 개의 스레드를 동시에 실행할 수 있답니다.각 개체는 하나의 잠금만 포함하고 모든 동기화된 메서드는 잠금이 필요하므로 클래스의 객체를 2개 생성하면 된다.따라서 동시에 실행하려면 두 개의 개체를 만든 다음 해당 개체 참조를 사용하여 실행해 보십시오.

두 개의 다른 스레드 단일 개체에서 공통 동기화된 메서드를 실행하며, 개체가 동일하므로 하나의 스레드가 동기화된 메서드와 함께 사용할 때 잠금을 확인해야 하며, 잠금이 활성화된 경우 이 스레드는 대기 상태로 전환되며, 잠금이 비활성화된 경우 객체에 액세스할 수 있으며, 접근하는 동안 잠금이 활성화되며,실행이 완료되어야만 잠금을 해제할 수 있다.다른 스레드가 도착하면, 그것은 잠금을 확인할 것이다. 왜냐하면 잠금이 해제되면 두 번째 스레드가 객체에 접근하여 실행될 때까지 잠금을 활성화할 것이기 때문이다.따라서 두 스레드가 동시에 실행되지 않고 두 스레드가 하나씩 실행되며, 두 스레드가 서로 다른 개체에 대해 동기화된 방법을 사용할 때 두 스레드가 동시에 실행된다.

참조URL: https://stackoverflow.com/questions/15438727/if-i-synchronized-two-methods-on-the-same-class-can-they-run-simultaneously

반응형