Java 클래스 잠금, 객체 잠금, 개인 잠금 충돌 테스트
1. 관련 약정
뒷글의 묘사를 명확히 하기 위해 본고가 언급한 자물쇠에 대한 정의는 다음과 같다.
1. 클래스 자물쇠: 코드에 있는 방법에static과synchronized의 자물쇠를 추가하거나synchronized(xx.class)의 코드 세그먼트, 예를 들어 아래의 increament()를 추가한다.
2. 대상 자물쇠: 코드에 있는 방법에synchronized의 자물쇠를 추가하거나synchronized(this)의 코드 세그먼트, 예를 들어 아래의synOnMethod()와synInMethod()를 추가한다.
3. 개인 자물쇠: 클래스 내부에서private Object lock과 같은 개인 속성을 설명하고 자물쇠를 채워야 하는 코드 세그먼트synchronized(lock), 예를 들어 다음의synMethod With Obj()를 표시합니다.
2. 테스트 코드
1. 시작 클래스 만들기 ObjectLock
public class ObjectLock {
public static void main(String[] args) {
System.out.println("start time = " + System.currentTimeMillis()+"ms");
LockTestClass test = new LockTestClass();
for (int i = 0; i < 3; i++) {
Thread thread = new ObjThread(test, i);
thread.start();
}
}
}
2. 동기화 방법을 시작하는 데 사용할 스레드 클래스 ObjThread를 작성합니다. (run 방법이 다른 테스트를 위해 조정될 수 있음을 주의하십시오.)
public class ObjThread extends Thread {
LockTestClass lock;
int i = 0;
public ObjThread(LockTestClass lock, int i) {
this.lock = lock;
this.i = i;
}
public void run() {
//
// lock.noSynMethod(this.getId(),this);
// 1, synchronized synInMethod
lock.synInMethod();
// 2, synchronized(this)
// lock.synOnMethod();
// , synchronized(object)
// lock.synMethodWithObj();
// , static synchronized increment
LockTestClass.increment();
}
}
3. 자물쇠를 추가하는 테스트 클래스 LockTestClass를 작성합니다. 여러 가지 자물쇠 추가 방법을 포함합니다.
public class LockTestClass {
//
private static int i = 0;
//
private Object object = new Object();
/**
* <p>
*
*
* @param threadID
* @param thread
*/
public void noSynMethod(long threadID, ObjThread thread) {
System.out.println("nosyn: class obj is " + thread + ", threadId is"
+ threadID);
}
/**
* 1
*/
public synchronized void synOnMethod() {
System.out.println("synOnMethod begins" + ", time = "
+ System.currentTimeMillis() + "ms");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synOnMethod ends");
}
/**
* 2, synchronized (this)
*/
public void synInMethod() {
synchronized (this) {
System.out.println("synInMethod begins" + ", time = "
+ System.currentTimeMillis() + "ms");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synInMethod ends");
}
}
/**
* 3
*/
public void synMethodWithObj() {
synchronized (object) {
System.out.println("synMethodWithObj begins" + ", time = "
+ System.currentTimeMillis() + "ms");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synMethodWithObj ends");
}
}
/**
*
*/
public static synchronized void increament() {
System.out.println("class synchronized. i = " + i + ", time = "
+ System.currentTimeMillis() + "ms");
i++;
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("class synchronized ends.");
}
}
3. 테스트 결과1. 클래스 잠금 및 객체 잠금 테스트, ObjectThread의 run 메서드는 다음과 같이 수정됩니다.
public void run() {
//
// lock.noSynMethod(this.getId(),this);
// 1, synchronized synInMethod
lock.synInMethod();
// 2, synchronized(this)
// lock.synOnMethod();
// , synchronized(object)
// lock.synMethodWithObj();
// , static synchronized increment
LockTestClass.increament();
}
터미널 출력:
start time = 1413101360231ms
synInMethod begins, time = 1413101360233ms
synInMethod ends
class synchronized. i = 0, time = 1413101362233ms
synInMethod begins, time = 1413101362233ms
class synchronized ends.
synInMethod ends
class synchronized. i = 1, time = 1413101364233ms
synInMethod begins, time = 1413101364233ms
class synchronized ends.
synInMethod ends
class synchronized. i = 2, time = 1413101366234ms
class synchronized ends.
대상 자물쇠 방법(syn In Mothod)이 첫 번째 시작할 때 클래스 자물쇠 방법(increament)보다 2초 빠른 것을 볼 수 있습니다. 이것은syn In Mehtod가 실행할 때 sleep가 2초 동안 실행된 increament이기 때문입니다. 이 두 방법은 하나의 라인을 사용하기 때문에 2초 느립니다. 만약에 increament가run에서syn In Method 앞에 놓으면 첫 번째 시작할 때 increament가 2초 빠릅니다.한편, 클래스 자물쇠 방법이 시작될 때 다른 라인의 대상 자물쇠 방법도 거의 동시에 시작된다는 것은 양자가 같은 자물쇠를 사용하지 않고 경쟁이 일어나지 않는다는 것을 의미한다.
결론: 유형 자물쇠와 대상 자물쇠는 경쟁이 일어나지 않고 양자의 자물쇠 추가 방법은 서로 영향을 주지 않는다.
2. 개인 자물쇠와 대상 자물쇠, ObjectThread의run 방법은 다음과 같이 수정됩니다.
public void run() {
//
// lock.noSynMethod(this.getId(),this);
// 1, synchronized synInMethod
lock.synInMethod();
// 2, synchronized(this)
// lock.synOnMethod();
// , synchronized(object)
lock.synMethodWithObj();
// , static synchronized increment
// LockTestClass.increament();
}
터미널 출력:
start time = 1413121912406ms
synInMethod begins, time = 1413121912407ms.
synInMethod ends.
synMethodWithObj begins, time = 1413121914407ms
synInMethod begins, time = 1413121914407ms.
synInMethod ends.
synMethodWithObj ends
synInMethod begins, time = 1413121916407ms.
synMethodWithObj begins, time = 1413121916407ms
synInMethod ends.
synMethodWithObj ends
synMethodWithObj begins, time = 1413121918407ms
synMethodWithObj ends
클래스 자물쇠와 대상 자물쇠와 매우 유사합니다.결론: 사유 자물쇠와 대상 자물쇠도 경쟁이 일어나지 않고 양자의 자물쇠 추가 방법은 서로 영향을 주지 않는다.
3. synchronized는 방법과 synchronized(this)에 직접 추가되며, ObjectThread의 run 방법은 다음과 같이 수정됩니다.
public void run() {
//
// lock.noSynMethod(this.getId(),this);
// 1, synchronized synInMethod
lock.synInMethod();
// 2, synchronized(this)
lock.synOnMethod();
// , synchronized(object)
// lock.synMethodWithObj();
// , static synchronized increment
// LockTestClass.increament();
}
터미널 출력:
start time = 1413102913278ms
synInMethod begins, time = 1413102913279ms
synInMethod ends
synInMethod begins, time = 1413102915279ms
synInMethod ends
synOnMethod begins, time = 1413102917279ms
synOnMethod ends
synInMethod begins, time = 1413102919279ms
synInMethod ends
synOnMethod begins, time = 1413102921279ms
synOnMethod ends
synOnMethod begins, time = 1413102923279ms
synOnMethod ends
이를 통해 알 수 있듯이 양자는 엄격하게 직렬 출력을 한다. (물론 다시 실행할 때synInMethod를 먼저 실행하느냐, 아니면synOnMethod를 먼저 실행하느냐가 확정된 것이 아니라 누가 자물쇠를 얻었느냐에 달려 있다.)결론:synchronized를 직접 방법에 추가하고synchronized(this)는 모두 현재 대상에 대한 자물쇠를 추가하는 것이다. 양자의 자물쇠 추가 방법은 경쟁 관계가 될 수 있고 같은 시간에 한 가지 방법만 실행할 수 있다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.