synchronized 원리에 깊이 들어가다
7227 단어 Java 동시 프로그래밍
synchronized 키워드는 주로 다음과 같은 3가지 응용 방식이 있다.실례를 수식하는 방법은 현재 실례에 자물쇠를 채우는 데 작용하고 동기화 코드에 들어가기 전에 현재 실례의 자물쇠를 획득해야 한다.정적 방법을 수식하고 현재 클래스 대상에 자물쇠를 채우는 데 작용하며 동기화 코드에 들어가기 전에 현재 클래스 대상의 자물쇠를 획득해야 한다.수식 코드 블록, 잠금 대상을 지정하고 주어진 대상에 잠금을 가하며 동기화 코드 라이브러리에 들어가기 전에 주어진 대상의 잠금을 획득해야 한다.
Java 객체 헤드
Java 객체 헤드는 다음과 같은 두 부분으로 구성됩니다. 1.MarkWord: 개체의 hashCode, 잠금 정보 또는 세대별 연령 또는 GC 로고 등의 정보를 저장합니다.Class Metadata Address: 유형 포인터는 객체의 클래스 메타데이터를 가리키며 JVM은 이 포인터를 통해 객체가 어떤 클래스의 인스턴스인지 결정합니다.
여기서 Mark Word는 기본적으로 객체의 HashCode, 세대별 나이, 잠금 표시 위치를 저장합니다.객체 헤드의 정보는 객체 자체가 정의한 데이터와 관련이 없는 추가 저장 비용이기 때문에 JVM의 공간 효율을 고려하여 MarkWord는 더 많은 유효한 데이터를 저장하기 위해 고정되지 않은 데이터 구조로 설계되었고 대상 자체의 상태에 따라 자신의 저장 공간을 복용할 것이다.
Synchronized는 헤비급 자물쇠입니다.
자바 초기 버전에서synchronized는 중량급 자물쇠에 속하고 효율이 낮다. 모니터 자물쇠(monitor)는 하부의 운영체제
Mutex Lock
에 의존하여 이루어진 것이고 운영체제가 라인 간의 전환을 실현할 때 사용자 상태에서 핵심 상태로 전환해야 하기 때문에 이 상태 간의 전환은 비교적 긴 시간이 필요하고 시간 원가가 상대적으로 높다. 이것은 초기의synchronized 효율이 낮은 이유이다.그러나 자바6 이후 자바는 JVM 차원에서 synchronized에 대한 최적화가 비교적 컸기 때문에 현재의 synchronized 자물쇠 효율도 잘 최적화되었다. 자바6 이후 자물쇠를 획득하고 방출하는 데 가져오는 성능 소모를 줄이기 위해 경량급 자물쇠와 편향 자물쇠를 도입하고 자전거 자물쇠를 기본적으로 열었다.
Synchronized 최적화
자물쇠의 상태는 모두 네 가지가 있는데 무자물쇠 상태, 편향 자물쇠, 경량급 자물쇠와 중량급 자물쇠가 있다.자물쇠의 경쟁에 따라 자물쇠는 편향 자물쇠에서 경량급 자물쇠로 승급할 수 있고 다시 승급할 수 있는 중량급 자물쇠이지만 자물쇠의 승급은 일방적이다. 즉, 낮은 자물쇠에서 높은 자물쇠로만 승급할 수 있고 자물쇠의 강등이 나타나지 않는다는 것이다.
public class StringBufferRemoveSync {
public void add(String str1, String str2) {
// StringBuffer , append synchronized ,
// sb ,J VM
StringBuffer sb = new StringBuffer();
sb.append(str1).append(str2);
}
public static void main(String[] args) {
StringBufferRemoveSync rmsync = new StringBufferRemoveSync();
for (int i = 0; i < 10000000; i++) {
rmsync.add("abc", "123");
}
}
}
int i = 0;
public void method1(){
for(int i = 0;i<1000;i++){
synchronized(this){ //1 synchronized
i++;
}
}
}
StringBuffer sb = new StringBuffer();
public void method2(){
for(int i = 0;i<1000;i++){
sb.append(i+""); // 2 synchronized
}
}
상기 코드에서 1의 경우 우리는synchronized의 위치를 수동으로 조정하여 잦은 잠금, 잠금 해제를 피할 수 있다면 2의 경우 잠금 조화로 조정할 수 밖에 없다(당연히synchronized에stringBuilder를 넣어도 되지만 만stringBuffer를 사용해야 한다면?).synchronized의 리셋 가능성
상호 배척 자물쇠의 디자인에서 볼 때 한 라인이 다른 라인이 가지고 있는 대상 자물쇠의 임계 자원을 조작하려고 시도할 때 막힌 상태에 처하지만 한 라인이 자신이 가지고 있는 대상 자물쇠의 임계 자원을 다시 요청할 때 이런 상황은 재접속 자물쇠에 속한다. 요청은 성공할 것이다. 자바에서synchronized는 원자성을 바탕으로 하는 내부 자물쇠 메커니즘으로 재접속할 수 있다.따라서 한 라인에서synchronized 방법을 호출하는 동시에 그 방법체 내부에서 이 대상의 다른synchronized 방법을 호출한다. 즉, 한 라인이 하나의 대상 자물쇠를 받은 후에 다시 이 대상 자물쇠를 요청하는 것은 허용된다. 이것이synchronized의 중입성이다.
```
int i = 0;
public void method(){
synchronized(this){// this
synchronized(this){// this , monitor ,
i++;
}
}
}
```
다시 들어가면 모니터의 계수기의 값이 1보다 클 수 있음을 주의하십시오.