최근에, 나는 비즈니스 로직의 정확성을 보장하기 위해 잠금이 필요한 직장에서 높은 동시성 시나리오를 만났으며, 잠금 후의 성능은 너무 큰 영향을 미치지 않아야합니다. 초기 아이디어는 타임 스탬프 및 ID와 같은 키워드를 통해 데이터를 잠그려면 다양한 유형의 데이터 처리의 동시성을 보장하는 것입니다. Java의 자체 API가 제공하는 잠금 세분화는 너무 커서 동시에 이러한 요구를 충족시키기가 어렵 기 때문에 몇 가지 간단한 확장을 직접 썼습니다 ...
1. 세그먼트 잠금
ConsperHashMap의 세분화 아이디어를 바탕으로 특정 수의 잠금이 생성되며,이를 사용하면 해당 잠금 장치가 키에 따라 반환됩니다. 이것은 여러 구현 중에서 가장 단순하고 가장 높은 성능 및 궁극적으로 채택 된 잠금 전략입니다. 코드는 다음과 같습니다.
/*** 세그먼트 잠금, 시스템은 특정 숫자의 원래 잠금을 제공하고, 들어오는 물체의 해시 값을 기반으로 해당 잠금을 얻고 잠금을 추가하십시오* 참고 : 잠긴 객체의 해시 값이 잠금 변경되면 잠금을 성공적으로 해제 할 수 없게 될 수 있습니다 !!! */public class segmentLock <t> {개인 정수 세그먼트 = 16; // 기본 세그먼트 번호 개인 최종 해시 맵 <inter, ReintrantLock> Lockmap = new Hashmap <> (); public segmentlock () {init (null, false); } public segmentLock (정수 수, 부울 박람회) {init (counts, fair); } private void init (정수 수, 부울 박람회) {if (counts! = null) {segments = counts; } for (int i = 0; i <segments; i ++) {lockmap.put (i, new ReintrantLock (fair)); }} public void lock (t key) {Reentrantlock lock = lockmap.get ((key.hashcode () >> 1) % 세그먼트); lock.lock (); } public void unlock (t key) {ReentrantLock lock = lockmap.get ((key.hashcode () >> 1) % 세그먼트); lock.unlock (); }}2. 해시 잠금
위의 세그먼트로 된 잠금 장치를 기반으로 개발 된 두 번째 잠금 전략은 진정한 세그레이드 잠금 잠금 장치를 달성하는 것입니다. 해시 값이 다른 각 객체는 자체 독립 잠금을 얻을 수 있습니다. 테스트에서 잠긴 코드가 빠르게 실행되면 효율이 세그먼트 잠금보다 약 30% 느려집니다. 오랜 시간이 걸리는 작업이 있다면 성능 감소가 더 좋을 것입니다. 코드는 다음과 같습니다.
공개 클래스 해시록 <t> {개인 부울 isfair = 거짓; 개인 최종 세그먼트 락 <T> segmentLock = new SegmentLock <> (); // 세그먼트 잠금 개인 최종 동의어 동력 동력 동력 동력 동력 동력 동력 동의어 <t, lockinfo> lekmap = new ConcurrenThashMap <> (); public hashlock () {} public hashlock (부울 박람회) {isfair = fair; } public void lock (t key) {lockinfo lockinfo; segmentlock.lock (키); try {lockinfo = lockmap.get (key); if (lockinfo == null) {lockinfo = new Lockinfo (isfair); lockmap.put (key, lockinfo); } else {lockinfo.count.incrementandget (); }} 마침내 {segmentLock.unlock (키); } lockinfo.lock.lock (); } public void unlock (t key) {lockinfo lockinfo = lockmap.get (키); if (lockinfo.count.get () == 1) {segmentlock.lock (키); try {if (lockinfo.count.get () == 1) {lockmap.remove (key); }} 마침내 {segmentLock.unlock (키); }} lockinfo.count.decrementandget (); lockinfo.unlock (); } private static class lockinfo {public retrantlock lek; public atomicinteger count = 새로운 atomicinteger (1); Private Lockinfo (부울 페어) {this.lock = 새로운 재진입 락 (페어); } public void lock () {this.lock.lock (); } public void unlock () {this.lock.unlock (); }}}3. 약한 참조 잠금
해시 잠금 장치는 자물쇠 생성 및 파괴의 동기화를 보장하기 위해 세그먼트로 된 잠금 장치가 도입 되었기 때문에 항상 결함이 있으므로 더 나은 성능과 더 미세한 잠금 잠금 장치를 찾기 위해 세 번째 잠금 장치가 작성되었습니다. 이 자물쇠에 대한 아이디어는 Java에서 약한 참조의 도움으로 자물쇠를 만들고 추가 소비를 피하기 위해 JVM의 쓰레기 수집으로 잠금의 파괴를 넘겨주는 것입니다.
ConsurenThashMap이 잠금 컨테이너로 사용되기 때문에 세그먼트 된 잠금 장치를 실제로 제거 할 수 없다는 것은 약간 유감입니다. 이 잠금의 성능은 해시록의 성능보다 약 10% 빠릅니다. 잠금 코드 :
/*** 약한 참조 잠금, 각각의 독립 해시에 독립적 인 잠금 함수를 제공합니다.*/public class weakhashlock <t> {private consurethashmap <t, 약점은 letrantlock >> lockmap = new ConcurrenTashMap <> (); Private ReferenceQueue <reentrantlock> queue = new ReferenceQueue <> (); public reintrantlock get (t key) {if (lockmap.size ()> 1000) {clearemptyref (); } 약점 <reentrantlock> lockref = lockmap.get (키); ReintrantLock Lock = (lockref == null? null : lockref.get ()); while (lock == null) {lockmap.putifabsent (key, new exceplockref <> (new ReintrantLock (), 큐, 키); lockref = lockmap.get (키); lock = (lockref == null? null : lockref.get ()); if (lock! = null) {리턴 잠금; } clearemptyref (); } 리턴 잠금; } @SuppressWarnings ( "확인되지 않은") private void clearEmptyRef () {참조 <? 재 렌트 런 락> ref 확장; while ((ref = queue.poll ())! = null) {weachlockref <t,? 재 렌트 링크를 확장합니다> 약한 lockref = (약한 lockref <t,? extends reintrantlock>) ref; lockmap.remove (약한 lockref.key); }} private static final class excerlockref <t, k> extends extreference <k> {final t key; private weachlockref (k 참조, 참조 Quesure <? super k> q, t key) {super (참조, q); this.key = 키; }}}추신
처음에는 Locksupport와 AQ를 사용하여 세밀한 자물쇠를 구현하고 싶었습니다. 내가 썼을 때, 나는 내가 구현하고있는 것들이 원주민 Java 자물쇠와 크게 다르지 않다는 것을 알았으므로, 나는 많은 시간을 낭비하는 Java 자신의 자물쇠의 캡슐화를 포기했다.
실제로,이 세분화 된 잠금 장치를 구현 한 후, 우리는 세분화 아이디어를 통해 특수 스레드에 데이터를 제출하는 것과 같은 새로운 아이디어를 가지고있어 많은 스레드의 차단 시간을 줄이고 향후 탐색으로 남겨 둘 수 있습니다 ...