클래스 잠금과 개체 잠금이 충돌합니까? 객체 잠금과 개인 잠금이 충돌합니까? 예제를 통한 일러스트레이션.
1. 관련 계약
다음 설명을 명확히 하기 위해 먼저 이 기사에 포함된 잠금의 관련 정의에 대해 다음 규칙을 적용합니다.
1. 클래스 잠금: 아래의 increament()와 같이 코드의 메서드 또는 동기화된(xxx.class) 코드 세그먼트에 정적 및 동기화된 잠금을 추가합니다.
2. 객체 잠금: 코드의 메소드에 동기화 잠금을 추가하거나 아래의 synOnMethod() 및 synInMethod()와 같은 동기화(this) 코드 세그먼트를 추가합니다.
3. Private lock : 클래스 내부에 private Object lock 등의 private 속성을 선언하고, 아래의 synMethodWithObj() 와 같이 잠궈야 하는 코드 세그먼트를 동기화(잠금)합니다.
2. 테스트 코드
1. 시작 클래스 ObjectLock 작성
다음과 같이 코드 코드를 복사합니다.
공개 클래스 ObjectLock {
공개 정적 무효 메인(String[] args) {
System.out.println("시작 시간 = " + System.currentTimeMillis()+"ms");
LockTestClass 테스트 = new LockTestClass();
for (int i = 0; i < 3; i++) {
스레드 스레드 = new ObjThread(test, i);
thread.start();
}
}
}
2. 동기화 방법을 시작하기 위해 스레드 클래스 ObjThread를 작성합니다. 실행 방법은 다른 테스트에 맞게 조정될 수 있습니다.
다음과 같이 코드 코드를 복사합니다.
공개 클래스 ObjThread는 Thread {를 확장합니다.
LockTestClass 잠금;
int i = 0;
공개 ObjThread(LockTestClass 잠금, int i) {
this.lock = 잠금;
this.i = 나;
}
공개 무효 실행() {
//무잠금 방식
//lock.noSynMethod(this.getId(),this);
//객체 잠금 방법 1, 동기화된 synInMethod 사용
lock.synInMethod();
//객체 잠금 방법 2, 동기화(this) 방법 사용
//lock.synOnMethod();
//동기화된(객체) 메서드를 사용한 개인 잠금 메서드
//lock.synMethodWithObj();
//정적 동기화 증분 방식을 사용하는 클래스 잠금 방식
LockTestClass.increment();
}
}
3. 다양한 잠금 방법을 포함하여 다른 잠금 테스트 클래스 LockTestClass를 작성합니다.
다음과 같이 코드 코드를 복사합니다.
공개 클래스 LockTestClass {
//클래스 잠금 계산에 사용됩니다.
개인 정적 int i = 0;
//개인 잠금
개인 개체 개체 = 새 개체();
/**
* <p>
* 락프리 방식
*
* @param 스레드ID
* @param 스레드
*/
공개 무효 noSynMethod(긴 스레드ID, ObjThread 스레드) {
System.out.println("nosyn: 클래스 obj는 " + thread + ", threadId는"
+ 스레드 ID);
}
/**
* 객체 잠금 방법 1
*/
공개 동기화 무효 synOnMethod() {
System.out.println("synOnMethod 시작" + ", time = "
+ System.currentTimeMillis() + "ms");
노력하다 {
Thread.sleep(2000L);
} 잡기(InterruptedException e) {
e.printStackTrace();
}
System.out.println("synOnMethod가 종료됩니다.");
}
/**
* 객체 잠금 방법 2, 동기화(this)를 사용하여 잠금
*/
공공 무효 synInMethod() {
동기화됨 (이것) {
System.out.println("synInMethod 시작" + ", time = "
+ System.currentTimeMillis() + "ms");
노력하다 {
Thread.sleep(2000L);
} 잡기(InterruptedException e) {
e.printStackTrace();
}
System.out.println("synInMethod가 종료됩니다.");
}
}
/**
* 객체 잠금 방법 3
*/
공공 무효 synMethodWithObj() {
동기화됨(객체) {
System.out.println("synMethodWithObj 시작" + ", time = "
+ System.currentTimeMillis() + "ms");
노력하다 {
Thread.sleep(2000L);
} 잡기(InterruptedException e) {
e.printStackTrace();
}
System.out.println("synMethodWithObj 종료");
}
}
/**
* 클래스 잠금
*/
공개 정적 동기화 무효 증가() {
System.out.println("클래스가 동기화되었습니다. i = " + i + ", time = "
+ System.currentTimeMillis() + "ms");
나++;
노력하다 {
Thread.sleep(2000L);
} 잡기(InterruptedException e) {
e.printStackTrace();
}
System.out.println("클래스 동기화가 종료됩니다.");
}
}
3. 테스트 결과
1. 클래스 잠금 및 개체 잠금을 테스트하려면 ObjectThread의 run 메서드를 다음과 같이 수정합니다.
다음과 같이 코드 코드를 복사합니다.
공개 무효 실행() {
//무잠금 방식
//lock.noSynMethod(this.getId(),this);
//객체 잠금 방법 1, 동기화된 synInMethod 사용
lock.synInMethod();
//객체 잠금 방법 2, 동기화(this) 방법 사용
//lock.synOnMethod();
//동기화된(객체) 메서드를 사용한 개인 잠금 메서드
//lock.synMethodWithObj();
//정적 동기화 증분 방식을 사용하는 클래스 잠금 방식
LockTestClass.increament();
}
터미널 출력:
다음과 같이 코드 코드를 복사합니다.
시작 시간 = 1413101360231ms
synInMethod 시작, 시간 = 1413101360233ms
synInMethod가 종료됩니다.
클래스가 동기화되었습니다. i = 0, 시간 = 1413101362233ms
synInMethod 시작, 시간 = 1413101362233ms
클래스 동기화가 종료됩니다.
synInMethod가 종료됩니다.
클래스가 동기화되었습니다. i = 1, 시간 = 1413101364233ms
synInMethod 시작, 시간 = 1413101364233ms
클래스 동기화가 종료됩니다.
synInMethod가 종료됩니다.
클래스가 동기화되었습니다. i = 2, 시간 = 1413101366234ms
클래스 동기화가 종료됩니다.
처음 시작할 때 객체 잠금 방식(synInMothod)이 클래스 잠금 방식(증분)보다 2초 빠른 것을 알 수 있는데, 이는 synInMehtod가 실행되면 2초간 sleep한 후 증가를 실행하기 때문이다. 메소드는 동일한 스레드를 공유하므로 증가가 실행 시 synInMethod 앞에 배치되면 처음 시작될 때 증가가 2초 더 빨라집니다.
클래스 잠금 방법이 시작되면 다른 스레드의 개체 잠금 방법도 거의 동시에 시작됩니다. 이는 두 스레드가 동일한 잠금을 사용하지 않으며 경쟁이 없음을 나타냅니다.
결론: 클래스 잠금과 개체 잠금은 경쟁하지 않으며 잠금 방법은 서로 영향을 미치지 않습니다.
2. 개인 잠금 및 개체 잠금, ObjectThread의 실행 메서드는 다음과 같이 수정됩니다.
다음과 같이 코드 코드를 복사합니다.
공개 무효 실행() {
//무잠금 방식
//lock.noSynMethod(this.getId(),this);
//객체 잠금 방법 1, 동기화된 synInMethod 사용
lock.synInMethod();
//객체 잠금 방법 2, 동기화(this) 방법 사용
//lock.synOnMethod();
//동기화된(객체) 메서드를 사용한 개인 잠금 메서드
lock.synMethodWithObj();
//정적 동기화 증분 방식을 사용하는 클래스 잠금 방식
//LockTestClass.increament();
}
터미널 출력:
다음과 같이 코드 코드를 복사합니다.
시작 시간 = 1413121912406ms
synInMethod가 시작되고 시간 = 1413121912407ms.
synInMethod가 종료됩니다.
synMethodWithObj가 시작되고 시간 = 1413121914407ms
synInMethod가 시작되고 시간 = 1413121914407ms.
synInMethod가 종료됩니다.
synMethodWithObj가 끝납니다.
synInMethod가 시작되고 시간 = 1413121916407ms.
synMethodWithObj가 시작되고 시간 = 1413121916407ms
synInMethod가 종료됩니다.
synMethodWithObj가 끝납니다.
synMethodWithObj가 시작되고 시간 = 1413121918407ms
synMethodWithObj가 끝납니다.
클래스 잠금 및 개체 잠금과 매우 유사합니다.
결론: 개인 잠금과 개체 잠금은 경쟁하지 않으며 잠금 방법은 서로 영향을 미치지 않습니다.
3.Synchronized를 메소드에 직접 추가하여 동기화(this)하고, ObjectThread의 run 메소드를 다음과 같이 수정합니다.
다음과 같이 코드 코드를 복사합니다.
공개 무효 실행() {
//무잠금 방식
//lock.noSynMethod(this.getId(),this);
//객체 잠금 방법 1, 동기화된 synInMethod 사용
lock.synInMethod();
//객체 잠금 방법 2, 동기화(this) 방법 사용
lock.synOnMethod();
//동기화된(객체) 메서드를 사용한 개인 잠금 메서드
//lock.synMethodWithObj();
//정적 동기화 증분 방식을 사용하는 클래스 잠금 방식
//LockTestClass.increament();
}
터미널 출력:
다음과 같이 코드 코드를 복사합니다.
시작 시간 = 1413102913278ms
synInMethod 시작, 시간 = 1413102913279ms
synInMethod가 종료됩니다.
synInMethod 시작, 시간 = 1413102915279ms
synInMethod가 종료됩니다.
synOnMethod 시작, 시간 = 1413102917279ms
synOnMethod가 종료됩니다.
synInMethod 시작, 시간 = 1413102919279ms
synInMethod가 종료됩니다.
synOnMethod 시작, 시간 = 1413102921279ms
synOnMethod가 종료됩니다.
synOnMethod 시작, 시간 = 1413102923279ms
synOnMethod가 종료됩니다.
보시다시피, 두 출력은 엄격하게 직렬로 이루어집니다. (물론 다시 실행할 때 synInMethod 또는 synOnMethod가 먼저 실행되는지 여부는 잠금을 획득한 사람에 따라 결정되지 않습니다.)
결론: 메소드에 직접 추가된 동기화 및 동기화(this)는 둘 다 현재 객체를 잠그며 경쟁 관계에 있으며 동시에 하나의 메소드만 실행할 수 있습니다.