Java 키워드 동기화 원리 및 잠금 상태 예시 분석
1. Java의 잠금 개념
스핀 잠금: 스레드가 잠금을 획득할 때 다른 스레드가 잠금을 획득한 경우 스레드는 루프에서 기다린 다음 계속해서 잠금을 결정하는 것을 의미합니다. 잠금을 성공적으로 획득할 수 있으면 잠금을 획득할 때까지 루프가 종료되지 않습니다.
낙관적 잠금: 충돌이 없다고 가정하고 데이터 수정 시 이전에 얻은 데이터와 일치하지 않는 데이터가 발견되면 최신 데이터를 읽고 다시 수정을 시도합니다.
비관적 잠금: 동시성 충돌이 발생할 것이라고 가정하고 데이터와 관련된 모든 작업을 동기화하고 데이터 읽기부터 잠금을 시작합니다.
배타적 잠금(쓰기): 리소스에 쓰기 잠금을 추가하면 스레드가 리소스를 수정할 수 있으며 다른 스레드는 리소스를 다시 잠글 수 없습니다(단일 쓰기).
공유 잠금(읽기): 리소스에 읽기 잠금을 추가한 후에는 읽을 수만 있고 수정할 수는 없습니다. 다른 스레드는 읽기 잠금만 추가할 수 있고 쓰기 잠금(다중)을 추가할 수 없습니다. 그냥 세마포어(semaphore)라고 생각하시면 됩니다.
재진입 잠금 및 비재진입 잠금: 스레드가 잠금을 획득한 후 동일한 잠금으로 동기화된 다른 코드를 자유롭게 입력할 수 있습니다.
공정한 잠금 & 불공정한 잠금: 잠금을 놓고 경쟁하는 순서는 선착순이면 공정합니다. 즉, 자물쇠를 잡는 순서와 자물쇠를 잡는 순서가 동일하다는 것이 보장된다면 공정한 자물쇠이다.
2. 동기화 키워드 동기화 기능
특징: 재진입, 독점, 비관적 잠금.
잠금 관련 최적화:
잠금 제거: 잠금 제거를 활성화하는 매개변수는
-XX:+DoEscapeAnalytic
,-XX:+EliminateLocks
입니다.-XX:+DoEscapeAnalysis
、-XX:+EliminateLocks
。锁粗化:JDK做了锁粗化的优化,但我们自己可从代码层面优化。
1、锁消除示例
/** * 锁消除示例,JIT即时编译,进行了锁消除 * @author 刘亚楼 * @date 2020/1/16 */ public class LockEliminationExample { /** * StringBuilder线程不安全,StringBuffer用了synchronized关键字,是线程安全的 * 针对下面这种单线程加锁、解锁操作,JIT会进行优化,进行锁消除 */ public static void eliminateLock() { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("a"); stringBuffer.append("b"); stringBuffer.append("c"); stringBuffer.append("a"); stringBuffer.append("b"); stringBuffer.append("c"); stringBuffer.append("a"); stringBuffer.append("b"); stringBuffer.append("c"); } }
2、锁粗化示例
/** * 锁粗化示例 * @author 刘亚楼 * @date 2020/1/16 */ public class LockCoarseningExample { /** * 针对下面这种无意义的加锁操作,JIT会进行优化,对变量i的所有操作放到一个同步代码块里 */ public static void lockCoarsening() { int i = 0; synchronized (LockCoarseningExample.class) { i++; } synchronized (LockCoarseningExample.class) { i--; } synchronized (LockCoarseningExample.class) { i++; } synchronized (LockCoarseningExample.class) { i++; i--; i++; } } }
备注:锁消除和锁粗化的区别在于锁消除是针对单个线程重复加解锁做的优化,最终没有锁的存在。而锁粗化不只是针对单线程,且最终还是有锁的存在。
三、synchronized关键字原理
1、关于Mark Word
首先,对象在堆中由对象头、实例数据和对齐填充组成。
对象头包含两部分信息,第一部分用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向锁id等,这部分数据官方称为"Mark Word"。
对象头的另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
synchronized实现的锁是通过改变对象头的"Mark Word"来实现的。
"Mard Word"在32位和64位的虚拟机(未开启压缩指针)中分别为32位和64位。32位虚拟机"Mark Word"如下:
2、锁的状态变化
(1) 无锁 → 轻量级锁
无锁变成轻量级锁时,多个线程会读取对象的对象头的无锁状态mark word内容,然后进行cas
操作进行修改,预期值是无锁状态mark word内容,新值是轻量级锁状态mark word内容,若修改成功,Lock record address
指向成功获取锁的线程的Lock Record
。
演示流程如下:
(2) 轻量级锁 → 重量级锁
由于未成功获取锁的线程会自旋,长时间自旋会消耗CPU资源,因此自旋到一定次数会进行锁升级,由轻量级锁转变为重量级锁。
重量级锁是通过object monitor(对象监视器)实现的,对象监视器包括entryList(锁池)、owner(持锁者)、waitSet(等待集合)等。
升级为重量级锁时对象头mark word的内容是monitor address(对象监视器地址),指向对象监视器。
演示流程如下:
备注:抢锁失败线程会进入entryList(锁池),在调用wait方法后,线程会进入waitSet(等待集合),waitSet中的线程被唤醒后会重新进入entryList。
(3) 关于偏向锁
加锁之后不解锁,针对单线程
所谓偏向就是偏心,单线程加锁之后就不再解锁,减少了加锁→业务处理→释放锁→加锁操作流程。
在JDK6以后,默认已经开启了偏向锁这个优化,通过JVM参数-XX:-UseBiasedLocking
1. 잠금 제거의 예
rrreee2. 잠금 해제의 예
rrreee🎜참고: 잠금 제거와 잠금 해제의 차이점은 잠금 제거가 일정 기간 동안 반복된다는 것입니다. 단일 스레드. 잠금 해제는 결국 잠금이 발생하지 않도록 최적화됩니다. 잠금 조잡화는 단일 스레드에만 적용되는 것이 아니라 궁극적으로 잠금에도 적용됩니다. 🎜🎜3. 동기화 키워드의 원리🎜1. 마크 워드에 대하여
🎜먼저 힙의 객체는 객체 헤더, 인스턴스 데이터, 정렬 패딩으로 구성됩니다. 🎜🎜객체 헤더에는 두 부분의 정보가 포함되어 있습니다. 첫 번째 부분은 해시 코드, GC 생성 기간, 잠금 상태 플래그, 스레드가 보유한 잠금, 편향된 잠금 ID 등과 같은 객체 자체의 런타임 데이터를 저장하는 데 사용됩니다. . 이 부분은 공식적인 데이터입니다. "마크 워드(Mark Word)"라고 합니다. 🎜🎜객체 헤더의 다른 부분은 객체의 클래스 메타데이터에 대한 포인터인 유형 포인터입니다. 가상 머신은 이 포인터를 사용하여 객체가 어떤 클래스의 인스턴스인지 결정합니다. 🎜🎜동기화로 구현된 잠금은 개체 헤더의 "마크 워드"를 변경하여 구현됩니다. 🎜🎜"Mard Word"는 32비트 및 64비트 가상 머신에서 각각 32비트 및 64비트입니다(압축 포인터는 켜지지 않음). 32비트 가상 머신 "Mark Word"는 다음과 같습니다. 🎜🎜
2. 잠금 상태 변경
(1) 잠금 없음→ 경량 잠금
🎜 잠금 없음이 경량 잠금이 되면 다중 스레드 개체 헤더의 잠금 해제 상태 표시 단어 내용을 읽은 다음cas
작업을 수행하여 이를 수정합니다. 예상 값은 잠금 해제 상태 표시 단어 내용이고 새 값은 경량 잠금 상태 표시 단어 내용이 성공적으로 수정된 경우 잠금 레코드 주소
는 잠금을 성공적으로 획득한 스레드의 잠금 레코드
를 가리킵니다. 🎜🎜시연 과정은 다음과 같습니다. 🎜🎜
(2) 경량 잠금→ 중량 잠금
🎜 잠금 획득에 실패한 스레드가 회전하게 되므로 장기 회전은 CPU 리소스를 소비하게 되므로 회전이 일정 수준에 도달하게 됩니다. 제한 잠금 장치는 경량 잠금 장치에서 중량 잠금 장치로 여러 번 업그레이드됩니다. 🎜🎜헤비웨이트 잠금은 EntryList(잠금 풀), 소유자(잠금 보유자), waitSet(대기 세트) 등을 포함하는 개체 모니터를 통해 구현됩니다. 🎜🎜중량 잠금 장치로 업그레이드할 때 개체 헤더 표시 단어의 내용은 개체 모니터를 가리키는 모니터 주소(개체 모니터 주소)입니다. 🎜🎜시연 과정은 다음과 같습니다. 🎜🎜
(3) 편향된 잠금 정보
🎜단일 스레드의 경우 잠금 후 잠금 해제 없음🎜🎜 소위 바이어스는 단일 스레드 잠금 후에는 더 이상 잠금 해제되지 않으므로 잠금(비즈니스 처리)이 줄어듭니다. ;잠금 해제→잠금 작업 과정입니다. 🎜🎜JDK6 이후에는 바이어스 잠금 최적화가 기본적으로 활성화되어 있습니다. 바이어스 잠금은 JVM 매개변수-XX:-UseBiasedLocking
을 통해 비활성화됩니다. 바이어스 잠금이 켜져 있으면 하나의 스레드만 잡을 수 있습니다. 잠금을 해제하고 바이어스를 얻습니다. 🎜🎜바이어스 잠금 표시 단어에 대한 내용은 다음과 같습니다. 🎜🎜🎜🎜바이어스 표시는 처음에는 유용하지만 경합이 발생한 후에는 쓸모가 없습니다.
편향 잠금의 본질은 잠금이 없다는 것입니다. 잠금에 대한 다중 스레드 경쟁이 없으면 JVM은 이를 단일 스레드로 간주하고 동기화가 필요하지 않습니다.
참고: JVM의 작업을 줄이기 위해 JVM 하단에서 여러 작업을 통해 동기화를 구현합니다. 경합이 없으면 동기화 작업을 수행할 필요가 없습니다.
(4) 전체 잠금 업그레이드 프로세스
바이어스 잠금이 켜지지 않은 경우 잠금 없는 상태에서 먼저 경량 잠금으로 업그레이드되고, 경량 잠금에서 중량 잠금으로 어느 정도 업그레이드됩니다.
바이어스 잠금이 켜져 있으면 두 가지 상황이 있습니다.
잠금이 점유되어 있지 않으면 잠금 없음으로 업그레이드되고 잠금 없음이 경량 잠금으로 업그레이드된 다음 경량 잠금 장치가 중량 잠금 장치로 업그레이드됩니다.
자물쇠가 점유되면 경량자물쇠로 업그레이드 되고, 이후 경량자물쇠에서 중량자물쇠로 업그레이드됩니다.
위 내용은 Java 키워드 동기화 원리 및 잠금 상태 예시 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Java의 난수 생성기 안내. 여기서는 예제를 통해 Java의 함수와 예제를 통해 두 가지 다른 생성기에 대해 설명합니다.

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

Java의 TimeStamp to Date 안내. 여기서는 소개와 예제와 함께 Java에서 타임스탬프를 날짜로 변환하는 방법에 대해서도 설명합니다.

Java는 초보자와 숙련된 개발자 모두가 배울 수 있는 인기 있는 프로그래밍 언어입니다. 이 튜토리얼은 기본 개념부터 시작하여 고급 주제를 통해 진행됩니다. Java Development Kit를 설치한 후 간단한 "Hello, World!" 프로그램을 작성하여 프로그래밍을 연습할 수 있습니다. 코드를 이해한 후 명령 프롬프트를 사용하여 프로그램을 컴파일하고 실행하면 "Hello, World!"가 콘솔에 출력됩니다. Java를 배우면 프로그래밍 여정이 시작되고, 숙달이 깊어짐에 따라 더 복잡한 애플리케이션을 만들 수 있습니다.
