Java 5이므로 java.util.concurrent.locks 패키지에는 일부 잠금 구현이 포함되어 있으므로 더 이상 자물쇠를 구현할 필요가 없습니다. 그러나 여전히 이러한 자물쇠를 사용하는 방법을 이해해야합니다.
간단한 자물쇠
Java의 동기화 블록부터 시작하겠습니다.
공개 클래스 카운터 {private int count = 0; public int inc () {synchronized (this) {return ++ count; }}}Inc () 메소드에 동기화 된 (이) 코드 블록이 있음을 알 수 있습니다. 이 코드 블록은 하나의 스레드 만 동시에 리턴 ++ 카운트를 실행할 수 있도록 할 수 있습니다. 동기화 된 동기화 블록의 코드가 더 복잡 할 수 있지만 ++ 카운트의 간단한 작동은 스레드 동기화의 의미를 표현하기에 충분합니다.
다음 카운터 클래스는 동일한 목표를 달성하기 위해 동기화 대신 잠금을 사용합니다.
공개 클래스 카운터 {개인 잠금 잠금 = 새로운 잠금 (); 개인 int count = 0; public int inc () {lock.lock (); int newCount = ++ 카운트; lock.unlock (); NewCount를 반환하십시오. }}Lock () 메소드는 잠금 인스턴스 객체를 잠금하므로 객체의 잠금 () 메서드를 호출하는 모든 스레드가 잠금 객체의 Unlock () 메소드가 호출 될 때까지 차단됩니다.
다음은 잠금 클래스의 간단한 구현입니다.
공개 클래스 카운터 {public class lock {private boolean islocked = false; public synchronized void lock () 던지기 인터럽트 exception {while (islocked) {wait (); } islocked = true; } public synchronized void unlock () {islocked = false; notify (); }}"스핀 잠금"이라고도하는 내부 내부 (Islocked) 루프를 기록하십시오. islocked가 true 일 때, 스레드 호출 lock ()가 차단하고 대기 () 호출을 기다립니다. Notify () 호출 (false wakeup이라고도 함)을 수신하지 않고 Thread가 Wait ()에서 돌아 오는 것을 방지하기 위해, 스레드가 깨어 난 후에도 안전하게 실행 될 수 있다고 생각하는 대신에 안전하게 실행 될 수 있는지 또는 다시 대기 해야하는지 여부를 결정하기 위해 Islocked 조건을 다시 확인합니다. IsLocked가 False 인 경우 현재 스레드는 while (islocked) 루프를 종료하고 islocked를 true로 다시 설정하여 Lock () 메서드를 호출하는 다른 스레드가 잠금 인스턴스에 잠금을 추가 할 수 있습니다.
스레드가 임계 섹션에서 코드를 완성하면 (lock ()과 unlock ()) 사이에 위치한 경우 unlock ()가 호출됩니다. Unlock ()의 실행은 false로 IsLocked를 다시 설정하고 wait () 함수를 lock () 메소드에서 호출 한 스레드 중 하나이며 대기 상태에 있습니다.
자물쇠의 재진성
Java의 동기화 된 동기화 블록은 재진입합니다. 즉, Java 스레드가 코드의 동기화 된 동기화 블록에 들어가서 동기화 블록에서 사용하는 동기화 객체에 해당하는 파이프의 잠금을 얻는 경우 스레드는 동일한 파이프 라인 객체에 의해 동기화 된 다른 Java 코드 블록을 입력 할 수 있습니다. 예는 다음과 같습니다.
공개 클래스 리엔 트랜트 {public synchronized outer () {inner (); } public synchronized inner () {// do do something}}OUTER () 및 inner ()는 동기화 된 선언으로 선언되며 Java의 동기화 된 (이) 블록과 동일합니다. 스레드가 OUTE ()을 호출하면 두 방법 (코드 블록)이 동일한 관리 객체 ( "this")에 의해 동기화되므로 OUTER ()에서 inner () 호출하는 데 아무런 문제가 없습니다. 스레드에 이미 파이프 객체에 잠금이있는 경우 파이프 객체와 동기화 된 모든 코드 블록에 액세스 할 수 있습니다. 이것은 재진입입니다. 스레드는 이미 가지고있는 잠금으로 동기화 된 모든 코드 블록을 입력 할 수 있습니다.
위에 주어진 잠금 구현은 재진입이 아닙니다. 다음과 같은 재진입 클래스를 다시 작성하면 스레드가 OUTER ()을 호출하면 내부 () 메소드의 lock.lock ()에서 차단됩니다.
공개 클래스 reintrant2 {잠금 잠금 = 새로운 잠금 (); public OUTER () {lock.lock (); 안의(); lock.unlock (); } public synchronized inner () {lock.lock (); // 잠금 장치를 수행합니다. Unlock (); }}OUTER ()을 호출하는 스레드는 먼저 잠금 인스턴스를 잠그고 내부 ()를 계속 호출합니다. 내부 () 메소드에서 스레드는 잠금 인스턴스를 다시 잠그려고 시도하고 조치가 실패합니다 (즉, 스레드가 차단됩니다).
잠금 해제 ()가 lock () 사이에서 두 번 호출되지 않으면 두 번째 호출이 차단됩니다. Lock ()의 구현을 본 후에는 그 이유가 분명하다는 것을 알게 될 것입니다.
공개 클래스 잠금 {부울 islocked = false; public synchronized void lock () 던지기 인터럽트 exception {while (islocked) {wait (); } islocked = true; } ...}스레드가 Lock () 메소드를 종료 할 수 있는지 여부는 while 루프 (스핀 잠금)의 조건에 의해 결정됩니다. 현재 판단 조건은 자물쇠 작동이 어떤 스레드를 잠그는 지 고려하지 않고 거짓일 때만 허용된다는 것입니다.
이 잠금 클래스를 다시 사용하기 위해서는 약간의 변경을해야합니다.
공개 클래스 잠금 {부울 islocked = false; 스레드 잠금 비 = null; int lockedCount = 0; public synchronized void lock () 던지기 인터럽트 exception {스레드 callingthread = thread.currentthread (); while (islocked && lockedby! = callingthread) {대기 (); } islocked = true; 잠금 카운트 ++; Lockedby = Callingthread; } public synchronized void unlock () {if (thread.currentthread () == this.lockedby) {lockedCount-; if (lockedCount == 0) {islocked = false; notify (); }}} ...}현재 While Loop (스핀 잠금)도 잠금 인스턴스를 잠긴 스레드를 고려합니다. 현재 잠금 객체가 잠겨 있지 않거나 (islocked = false) 또는 현재 호출 스레드가 잠금 인스턴스를 잠그는 경우, while 루프가 실행되지 않으며 스레드 호출 잠금 ()은 메소드를 종료 할 수 있습니다 (Translator 's Note : "현재 시맨틱에서"메소드를 종료 할 수 있습니다 "는 호출 대기 ()가 없음을 의미합니다.
또한 동일한 스레드의 횟수를 기록해야합니다. 그렇지 않으면, 하나의 unblock () 호출은 현재 잠금 장치가 여러 번 잠겨 있더라도 전체 잠금을 차단 해제합니다. 잠금 해제 () 호출이 해당 잠금 () 호출이 호출되는 횟수에 도달 할 때까지 잠금을 잠금 해제하기를 원하지 않습니다.
이제이 잠금 클래스는 재진입합니다.
자물쇠의 공정성
Java의 동기화 된 블록은 스레드가 입력하려는 순서를 보장하지 않습니다. 따라서 여러 스레드가 동일한 동기화 된 동기화 블록에 액세스하기 위해 계속 경쟁하면 하나 이상의 스레드가 액세스 할 수 없을 위험이 있습니다. 즉, 액세스는 항상 다른 스레드에 할당됩니다. 이 상황을 실 굶주림이라고합니다. 이 문제를 피하려면 잠금 장치는 공정성을 달성해야합니다. 이 기사에 표시된 잠금은 내부적으로 동기화 된 동기화 블록으로 구현되므로 공정하지는 않습니다.
최종 문서에서 Unlock ()을 호출하십시오
잠금 장치가 임계 영역을 보호하는 데 사용되고 임계 영역이 예외를 던질 수있는 경우, 마지막 문서에서 Unlock ()을 호출하는 것이 매우 중요합니다. 따라서 잠금 객체를 잠금 해제하여 다른 스레드가 계속 잠글 수 있도록합니다. 예는 다음과 같습니다.
lock.lock (); try {// 중요한 섹션 코드를 수행하십시오.이 간단한 구조는 임계 영역에서 예외가 발생하면 잠금 객체를 잠금 해제 할 수 있도록합니다. 최종 문서에서 잠금 해제 ()가 호출되지 않으면, 임계 섹션에 예외가 발생하면 잠금 객체는 잠긴 상태에 영원히 유지되므로 잠금 객체의 다른 모든 스레드가 잠금 객체를 호출하여 블록으로 연결합니다.
위는 Java 멀티 스레드 잠금에 대한 정보입니다. 우리는 향후 관련 정보를 계속 추가 할 것입니다. 이 사이트를 지원 해주셔서 감사합니다!