>  기사  >  Java  >  Java 잠금을 최적화하는 방법

Java 잠금을 최적화하는 방법

PHPz
PHPz앞으로
2023-05-16 08:16:051298검색

잠금 최적화

여기서 잠금 최적화는 주로 JVM에 의한 동기화 최적화를 의미합니다.

스핀락

차단 상태로의 뮤텍스 동기화는 비용이 많이 들므로 최대한 피해야 합니다. 많은 애플리케이션에서 공유 데이터는 짧은 기간 동안만 잠겨 있습니다. 스핀 잠금의 개념은 공유 데이터 잠금을 요청할 때 스레드가 일정 시간 동안 사용 중 루프(스핀)를 수행하도록 허용하는 것입니다. 이 기간 동안 잠금을 얻을 수 있으면 차단 상태로 들어가는 것을 피할 수 있습니다. .

스핀 잠금은 차단 상태로 들어가는 것을 방지하고 오버헤드를 줄일 수 있지만 CPU 시간을 차지하려면 바쁜 루프 작업이 필요합니다. 공유 데이터의 잠금 상태가 매우 짧은 시나리오에만 적합합니다.

적응형 스핀 잠금은 JDK 1.6에서 도입되었습니다. 적응형이란 회전 횟수가 더 이상 고정되지 않고 동일한 잠금 장치의 이전 회전 횟수와 잠금 소유자의 상태에 따라 결정된다는 의미입니다.

자물쇠 제거

잠금 제거는 경쟁이 있을 가능성이 없는 것으로 감지된 공유 데이터에 대한 잠금을 제거하는 것을 의미합니다.

잠금 제거는 주로 이스케이프 분석을 통해 지원됩니다. 힙의 공유 데이터가 탈출할 수 없고 다른 스레드에서 액세스할 수 없으면 해당 데이터를 개인 데이터로 처리하여 잠금을 제거할 수 있습니다.

잠긴 것처럼 보이지 않는 일부 코드의 경우 실제로는 많은 잠금이 암시적으로 추가됩니다. 예를 들어 다음 문자열 접합 코드는 암시적으로 잠금을 추가합니다.

​public static String concatString(String s1, String s2, String s3) { return s1 + s2 + s3 }

String은 불변 클래스이며, 컴파일러는 String의 접합을 자동으로 최적화합니다. JDK 1.5 이전에는 StringBuffer 객체의 연속 추가() 작업으로 변환되었습니다.

public static String concatString(String s1, String s2, String s3) { StringBuffer sb = new StringBuffer(s1) sb.append(s2); }

모든 Append() 메소드에는 동기화 블록이 있습니다. 가상 머신은 sb 변수를 관찰하고 해당 동적 범위가 concatString() 메서드 내에서 제한되어 있음을 빠르게 발견합니다. 즉, sb에 대한 모든 참조는 결코 concatString() 메서드 외부로 이스케이프되지 않으며 다른 스레드에서 액세스할 수 없으므로 제거할 수 있습니다.

잠금 러프닝

일련의 연속 작업이 동일한 개체를 반복적으로 잠그고 잠금 해제하는 경우 빈번한 잠금 작업으로 인해 성능이 저하됩니다.

이전 섹션의 예제 코드에 있는 연속된 추가() 메서드가 이 범주에 속합니다. 가상 머신은 이러한 일련의 조각화된 작업으로 인해 동일한 개체가 잠긴 것을 감지하면 잠금 범위를 전체 작업 순서 외부로 확장(거칠게)합니다. 이전 섹션의 샘플 코드는 첫 번째 추가() 작업 이전부터 마지막 ​​추가() 작업 이후까지 확장되었으므로 한 번만 잠그면 됩니다.

​경량 잠금장치

JDK 1.6에는 편향된 잠금과 경량 잠금이 도입되어 잠금이 잠금 해제, 편향, 경량 잠금 및 중량 잠금의 4가지 상태를 가질 수 있습니다.

중량 잠금은 일반적으로 동기화된 개체 잠금이라고도 합니다.

다음은 HotSpot 가상 머신 개체 헤더의 메모리 레이아웃입니다. 이러한 데이터를 Mark Word라고 합니다. 태그 비트는 오른쪽 상태 테이블에 제공되는 5가지 상태에 해당합니다. gc 상태로 표시된 것 외에도 다른 네 가지 상태가 이전에 도입되었습니다.

아래 그림의 왼쪽은 Thread의 가상 머신 스택입니다. Lock Record라는 영역의 일부가 경량 잠금 실행 과정에서 생성되며 잠금 개체의 Mark Word를 저장하는 데 사용됩니다. 오른쪽에는 Mark Word 및 기타 정보가 포함된 잠금 개체가 있습니다.

기존의 중량 잠금과 비교하여 경량 잠금은 CAS 작업을 사용하여 뮤텍스를 사용하는 중량 잠금의 오버헤드를 방지합니다. 대부분의 잠금에서는 전체 동기화 주기 동안 경쟁이 없으므로 동기화를 위해 뮤텍스를 사용할 필요가 없습니다. 먼저 CAS 작업을 사용하여 동기화하면 됩니다.

Lock 객체를 획득하려고 할 때 Lock 객체가 0 01로 표시되면 Lock 객체가 잠금 해제된 상태임을 의미합니다. 이때 가상머신은 현재 쓰레드의 가상머신 스택에 Lock Record를 생성한 후 CAS 연산을 이용하여 해당 객체의 Mark Word를 Lock Record 포인터로 업데이트한다. CAS 작업이 성공하면 스레드가 개체에 대한 잠금을 획득하고 개체의 Mark Word 잠금 태그가 00으로 변경되어 개체가 경량 잠금 상태에 있음을 나타냅니다.

CAS 작업이 실패하면 가상 머신은 먼저 개체의 Mark Word가 현재 스레드의 가상 머신 스택을 가리키는지 확인합니다. 그렇다면 현재 스레드가 이미 잠금 개체를 소유하고 있음을 의미하며 그런 다음 직접 잠금 개체에 들어갈 수 있습니다. 그렇지 않으면 잠금 개체가 다른 스레드에 의해 선점되었음을 의미합니다. 두 개 이상의 스레드가 동일한 잠금에 대해 경쟁하는 경우 경량 잠금은 더 이상 효과적이지 않으며 중량 잠금으로 확장해야 합니다.

바이어스 잠금

편향된 잠금의 개념은 잠금 개체를 획득하는 첫 번째 스레드를 선호하는 것입니다. 이 스레드는 잠금을 획득한 후 더 이상 동기화 작업을 수행할 필요가 없으며 CAS 작업도 더 이상 필요하지 않습니다.

스레드가 처음으로 잠금 개체를 획득하면 바이어스 상태로 들어가고 1 01로 표시됩니다. 동시에 CAS 작업을 사용하여 스레드 ID를 Mark Word에 기록합니다. CAS 작업이 성공하면 이 스레드는 이 잠금과 관련된 동기화 블록에 들어갈 때마다 동기화 작업을 수행할 필요가 없습니다.

다른 스레드가 이 잠금 개체를 획득하려고 하면 바이어스 상태(Revoke Bias)가 취소되고 잠금 해제 상태 또는 경량 잠금 상태로 돌아갑니다.

위 내용은 Java 잠금을 최적화하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제