Java rewrite lock의 설계 구조와 세부 사항은 무엇입니까?
소개
어떤 면접관들은 학생들에게 자물쇠의 원리를 설명한 후 새 자물쇠를 다시 작성하라고 하고, 화이트보드에 전반적인 아이디어와 코드 논리를 적어달라고 요청하는 것을 좋아합니다. 개인적으로 두 부분에 중점을 두고 있다고 생각합니다.
잠금 원리에 대한 이해가 어떻게 시작되었는지 살펴보세요. 소스 코드를 읽지 않았다면 온라인 기사를 읽어보거나 뒷면에 있는 인터뷰 질문을 통해서도 알 수 있습니다. 일반적인 원칙이지만 실제로 소스 코드를 본 적이 없거나 잠금 관련 프로젝트에 대한 경험이 없으면 그 자리에서 잠금 구현 코드를 작성하기가 어렵습니다.
생성할 필요는 없습니다. Java 잠금의 기존 API를 모방하기 위해 다시 작성하면 됩니다.
소스 코드를 읽어보셨다면 이 질문은 정말 간단합니다. 익숙한 자물쇠를 선택하여 따라하시면 됩니다.
1. 요구 사항
일반적으로 잠금을 사용자 정의할 때 요구 사항에 따라 정의합니다. 공유 잠금의 경우 공유 리소스와 같은 다양한 시나리오를 생각할 수 있습니다. 데이터베이스 링크에 대한 공유 액세스와 같이 읽기 잠금을 공유할 수 있습니다. 예를 들어 소켓 서버의 링크 수를 공유할 수 있습니다. 잠금을 정의하기 위해 데이터베이스 링크에 대한 공유 액세스 시나리오를 선택합니다.
2. 상세 설계
우리의 데이터베이스가 10개의 연결만 지원할 수 있는 독립형 mysql이라고 가정합니다. 데이터베이스 링크를 생성할 때 가장 원시적인 JDBC 방법을 사용합니다. 인터페이스를 사용합니다. JDBC는 링크 생성 프로세스를 캡슐화합니다. 이 인터페이스의 이름은 Create Link Interface입니다.
공유 액세스 데이터베이스 링크에 대한 전체 요구 사항은 다음과 같습니다. 결합된 모든 요청에 대한 mysql 링크 수는 10(포함)을 초과할 수 없습니다. 10을 초과하면 오류가 직접 보고됩니다.
이 맥락에서 우리는 다음 그림을 디자인했습니다.
이 디자인의 가장 중요한 부분은 잠금을 얻을 수 있는지 여부에 따라 mysql 링크를 얻을 수 있는지 여부를 결정한다는 것입니다. 그런 다음 링크를 얻을 수 있습니다. 그렇지 않으면 오류가 직접 보고됩니다.
그럼 구현된 코드를 살펴보겠습니다.
2.1. 잠금 정의
먼저 정의에는 두 가지 요소가 필요합니다.
잠금 정의: 외부에서 제공되는 동기화 잠금; 그리고 잠금 해제.
공유 잠금의 코드 구현은 다음과 같습니다.
// 共享不公平锁 public class ShareLock implements Serializable{ // 同步器 private final Sync sync; // 用于确保不能超过最大值 private final int maxCount; /** * 初始化时给同步器 sync 赋值 * count 代表可以获得共享锁的最大值 */ public ShareLock(int count) { this.sync = new Sync(count); maxCount = count; } /** * 获得锁 * @return true 表示成功获得锁,false 表示失败 */ public boolean lock(){ return sync.acquireByShared(1); } /** * 释放锁 * @return true 表示成功释放锁,false 表示失败 */ public boolean unLock(){ return sync.releaseShared(1); } }
위 코드에서 볼 수 있듯이 잠금 및 해제 잠금 구현은 동기화 장치 Sync의 기본 구현에 의존합니다.
유일하게 주목해야 할 점은 잠금이 주로 두 가지 측면에서 API 사양을 지정해야 한다는 것입니다.
API에 필요한 것은 잠금이 초기화될 때 나에게 전달해야 하는 매개변수입니다. 초기화되면 최대 공유 가능한 잠금 수를 전달해야 합니다.
자체 기능을 정의해야 합니다. 즉, 각 메서드의 입력 매개 변수와 출력 매개 변수를 정의해야 합니다. ShareLock 구현에는 잠금 및 해제를 위한 입력 매개변수가 없습니다. 이는 메서드에 1로 하드코딩되어 있으며, 이는 메서드가 실행될 때마다 잠금이 한 번만 잠기거나 해제될 수 있음을 의미합니다. 매개변수는 부울 값이고 true는 추가를 의미합니다. 잠금 또는 잠금 해제가 성공했음을 의미하고, false는 실패를 의미하며, 맨 아래 계층에서는 동기화 불공정 잠금을 사용합니다.
위의 사고 방식에는 방법론이 있습니다. 즉, 문제에 대해 생각할 때 두 가지 측면에서 시작할 수 있습니다. API란 무엇입니까? API에는 어떤 기능이 있나요?
2.2.동기화 장치 정의
Sync는 AQS를 직접 상속합니다. 코드는 다음과 같습니다.
class Sync extends AbstractQueuedSynchronizer { // 表示最多有 count 个共享锁可以获得 public Sync(int count) { setState(count); } // 获得 i 个锁 public boolean acquireByShared(int i) { // 自旋保证 CAS 一定可以成功 for(;;){ if(i<=0){ return false; } int state = getState(); // 如果没有锁可以获得,直接返回 false if(state <=0 ){ return false; } int expectState = state - i; // 如果要得到的锁不够了,直接返回 false if(expectState < 0 ){ return false; } // CAS 尝试得到锁,CAS 成功获得锁,失败继续 for 循环 if(compareAndSetState(state,expectState)){ return true; } } } // 释放 i 个锁 @Override protected boolean tryReleaseShared(int arg) { for(;;){ if(arg<=0){ return false; } int state = getState(); int expectState = state + arg; // 超过了 int 的最大值,或者 expectState 超过了我们的最大预期 if(expectState < 0 || expectState > maxCount){ log.error("state 超过预期,当前 state is {},计算出的 state is {}",state ,expectState); return false; } if(compareAndSetState(state, expectState)){ return true; } } } }
전체 코드에서 주의해야 할 점은 다음과 같습니다.
경계에 대한 판단. 입력 매개변수가 불법인지, 잠금이 해제되면 발생하지 않을까요? 불법 상태 등의 경계 문제가 예상됩니다. 이러한 문제에 대한 판단을 내리고 사고의 엄격함을 반영해야 합니다.
잠금을 해제하려면; , 동시 추가가 발생할 때 잠금을 잠그거나 해제할 때 성공적으로 재시도할 수 있도록 spin + CAS를 사용해야 합니다. Spin용으로 작성 시에는 무한 루프가 발생하지 않도록 주의가 필요하며, CAS 방식은 AQS에서 제공하는 것이므로 직접 작성하지 마십시오.
2.3.링크를 얻을 수 있는지 여부는 잠금을 얻을 수 있는지 여부에 따라 결정됩니다
잠금이 정의된 후에는 MysqlConnection이라는 Mysql 링크 도구 클래스를 작성했습니다. 주로 두 가지 큰 기능을 담당합니다:
JDBC를 통해 Mysql과의 링크 설정
요청이 너무 클 때 총 Mysql 링크 수가 10을 초과하지 않도록 잠금 기능과 결합.
먼저 MysqlConnection 초기화 코드를 살펴보겠습니다.
public class MysqlConnection { private final ShareLock lock; // maxConnectionSize 表示最大链接数 public MysqlConnection(int maxConnectionSize) { lock = new ShareLock(maxConnectionSize); } }
초기화 중에 최대 링크 수를 지정한 다음 이 값을 잠금에 전달해야 한다는 것을 알 수 있습니다. ShareLock 잠금 값의 상태입니다.
그런 다음 1을 완료하기 위해 비공개 메소드를 작성했습니다:
// 得到一个 mysql 链接,底层实现省略 private Connection getConnection(){}
그런 다음 2를 구현했으며 코드는 다음과 같습니다.
// 对外获取 mysql 链接的接口 // 这里不用try finally 的结构,获得锁实现底层不会有异常 // 即使出现未知异常,也无需释放锁 public Connection getLimitConnection() { if (lock.lock()) { return getConnection(); } return null; } // 对外释放 mysql 链接的接口 public boolean releaseLimitConnection() { return lock.unLock(); }
逻辑也比较简单,加锁时,如果获得了锁,就能返回 Mysql 的链接,释放锁时,在链接关闭成功之后,调用 releaseLimitConnection 方法即可,此方法会把锁的 state 状态加一,表示链接被释放了。
以上步骤,针对 Mysql 链接限制的场景锁就完成了。
3、测试
锁写好了,接着我们来测试一下,我们写了一个测试的 demo,代码如下:
public static void main(String[] args) { log.info("模仿开始获得 mysql 链接"); MysqlConnection mysqlConnection = new MysqlConnection(10); log.info("初始化 Mysql 链接最大只能获取 10 个"); for(int i =0 ;i<12;i++){ if(null != mysqlConnection.getLimitConnection()){ log.info("获得第{}个数据库链接成功",i+1); }else { log.info("获得第{}个数据库链接失败:数据库连接池已满",i+1); } } log.info("模仿开始释放 mysql 链接"); for(int i =0 ;i<12;i++){ if(mysqlConnection.releaseLimitConnection()){ log.info("释放第{}个数据库链接成功",i+1); }else { log.info("释放第{}个数据库链接失败",i+1); } } log.info("模仿结束"); }
以上代码逻辑如下:
获得 Mysql 链接逻辑:for 循环获取链接,1~10 都可以获得链接,11~12 获取不到链接,因为链接被用完了;释放锁逻辑:for 循环释放链接,1~10 都可以释放成功,11~12 释放失败。
我们看下运行结果,如下图:
从运行的结果,可以看出,我们实现的 ShareLock 锁已经完成了 Mysql 链接共享的场景了。
위 내용은 Java rewrite lock의 설계 구조와 세부 사항은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

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

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

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

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

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

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

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

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

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

뜨거운 주제











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

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

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

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

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

캡슐은 3 차원 기하학적 그림이며, 양쪽 끝에 실린더와 반구로 구성됩니다. 캡슐의 부피는 실린더의 부피와 양쪽 끝에 반구의 부피를 첨가하여 계산할 수 있습니다. 이 튜토리얼은 다른 방법을 사용하여 Java에서 주어진 캡슐의 부피를 계산하는 방법에 대해 논의합니다. 캡슐 볼륨 공식 캡슐 볼륨에 대한 공식은 다음과 같습니다. 캡슐 부피 = 원통형 볼륨 2 반구 볼륨 안에, R : 반구의 반경. H : 실린더의 높이 (반구 제외). 예 1 입력하다 반경 = 5 단위 높이 = 10 단위 산출 볼륨 = 1570.8 입방 단위 설명하다 공식을 사용하여 볼륨 계산 : 부피 = π × r2 × h (4

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