같은 클래스에서 두 개의 메소드를 동기화 하면 동일한 객체 에서 동시에 실행할 수 있습니까? 예를 들면 다음과 같습니다.
class A {
public synchronized void methodA() {
//method A
}
public synchronized void methodB() {
// method B
}
}
methodA()
두 개의 다른 스레드에서 동일한 객체에서 두 번 실행할 수 없다는 것을 알고 있습니다 . 에서 같은 것 methodB()
.
그러나 여전히 실행중인 methodB()
동안 다른 스레드에서 실행할 수 methodA()
있습니까? (같은 객체)
답변
두 방법 모두 같은 모니터를 잠급니다. 따라서 다른 스레드의 동일한 객체에서 동시에 실행할 수 없습니다 (두 방법 중 하나는 다른 방법이 완료 될 때까지 차단됨).
답변
예제에서 methodA와 methodB는 인스턴스 메소드입니다 (정적 메소드와 반대). 퍼팅 synchronized
스레드가 상기 방법은 스레드가 그 방법에서 코드를 실행을 시작하기 전에 호출되는 오브젝트 인스턴스에 대한 잠금 (이하 “극한 로크”)를 획득한다는 것을 인스턴스 메소드 수단에.
동기화 된 것으로 표시된 두 개의 다른 인스턴스 메소드가 있고 다른 스레드가 동일한 오브젝트에서 해당 메소드를 동시에 호출하는 경우 해당 스레드는 동일한 잠금을 위해 경합합니다. 한 스레드가 잠금을 획득하면 다른 모든 스레드는 해당 오브젝트의 모든 동기화 된 인스턴스 메소드에서 종료됩니다.
두 방법을 동시에 실행하려면 다음과 같이 다른 잠금을 사용해야합니다.
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
}
}
따라서 메소드 레벨에서 동기화는 단순히 동기화 됨 (this)을 의미합니다. 스레드가이 클래스의 메소드를 실행하는 경우 실행을 시작하기 전에 잠금을 확보하고 메소드 실행이 완료 될 때까지 보유합니다.
그러나 methodA ()가 계속 실행되는 동안 다른 스레드에서 methodB ()를 실행할 수 있습니까? (같은 객체)
실제로는 불가능합니다!
따라서 여러 스레드가 동일한 객체에서 동시에 여러 개의 동기화 된 메소드를 실행할 수 없습니다.
답변
명확하게 말하면 정적 동기화 및 비 정적 동기화 방법은 객체 수준 잠금 및 다른 클래스 수준 잠금이 있기 때문에 동시에 또는 동시에 실행될 수 있습니다.