[Java] 동기화 대 잠금


Answers

나는 이것들 중 어느 것이 실제로 더 나은지, 왜 그런지 궁금하다.

LockCondition (및 다른 새로운 concurrent 클래스)이 도구 상자의 도구 일 뿐이라는 것을 알았습니다. 나는 오래된 클로 해머 ( synchronized 키워드)로 필요한 모든 것을 할 수 있었지만, 어떤 상황에서는 사용하기가 어색했다. 고무 망치, 볼 - 핑 망치, 프라이 바 (prybar), 일부 못 펀치 (nunch punch) 등 도구 상자에 더 많은 도구를 추가하면 어색한 상황이 훨씬 더 간단 해졌습니다. 그러나 , 내 오래된 발톱 망치는 여전히 사용의 점유율을보고있다.

나는 하나가 다른 것보다 "더"훌륭하다고 생각하지 않지만, 오히려 각각은 다른 문제에 더 잘 맞는다. 간단히 말해서 synchronized 의 단순한 모델과 범위 지향적 특성은 코드의 버그로부터 나를 보호하는 데 도움이되지만보다 복잡한 시나리오에서는 이러한 이점이 때때로 방해가됩니다. 동시 패키지가 작성된이보다 복잡한 시나리오는 해결에 도움이됩니다. 그러나이 고급 구성을 사용하면 코드에서보다 명확하고 신중한 관리가 필요합니다.

===

나는 JavaDocLocksynchronized 의 차이점을 설명하는 훌륭한 역할을한다고 생각한다. (강조점은 내 것이다.)

잠금 구현은 동기화 된 메서드 및 문을 사용하여 얻을 수있는 것보다 더 광범위한 잠금 작업을 제공합니다. 그것들은, 보다 유연한 구조화를 가능하게 해 , 상당히 다른 속성을 가질 수가있어 관련의 복수의 Condition 객체를 지원할 가능성이 있습니다 .

...

동기화 된 메소드 또는 명령문을 사용하면 모든 객체와 관련된 암시 적 모니터 잠금에 대한 액세스가 제공되지만 모든 잠금 획득 및 해제가 블록 구조로 수행되도록합니다 . 다중 잠금획득 한 경우 반대 순서로 해제해야 하며 모든 잠금은 획득 된 동일한 어휘 범위에서 해제되어야합니다 .

동기화 된 메소드 및 명령문의 범위 지정 메커니즘은 모니터 잠금으로 프로그래밍하는 것이 훨씬 쉬우 며 잠금관련된 많은 일반적인 프로그래밍 오류를 방지 하는 데 도움 이되지만보다 유연한 방법으로 잠금을 사용해야하는 경우가 있습니다. 예를 들어, 동시에 액세스되는 데이터 구조를 탐색하기위한 일부 알고리즘 * 은 노드 A의 잠금을 획득 한 다음 노드 B의 잠금을 획득 한 다음 A를 해제하고 C를 획득하는 "수동 전달"또는 "체인 잠금" 그런 다음 B를 놓고 D를 얻는다. Lock 인터페이스의 구현은 다양한 범위 에서 잠금을 획득하고 해제 할 수 있도록 허용하고 여러 잠금을 임의 순서로 획득하고 해제 할 수 있도록하여 이러한 기술의 사용을 가능하게합니다.

이러한 유연성 증대로 인해 추가적인 책임이 따릅니다 . 블록 구조 잠금없으면 동기화 된 메소드 및 명령문에서 발생하는 잠금 자동 해제가 제거됩니다 . 대부분의 경우 다음 관용구를 사용해야합니다.

...

다른 범위에서 잠금 및 잠금 해제가 발생 하면 잠금 이 실행되는 동안 실행되는 모든 코드가 try-finally 또는 try-catch보호되어 필요한 경우 잠금이 해제되는지 확인해야합니다 .

잠금 구현은 잠금 을 획득하기 위한 비 차단 시도 (tryLock ()), 중단 될 수있는 잠금획득 하려는 시도 (lockInterruptibly () 및 획득 시도)를 제공하여 동기화 된 메소드 및 명령문을 사용하는 보다 추가 기능 을 제공합니다 타임 아웃 할 수있는 락 (tryLock (long, TimeUnit))

...

Question

java.util.concurrent API는 Lock 이라는 클래스를 제공합니다. Lock 은 중요한 리소스에 액세스하기 위해 기본적으로 컨트롤을 직렬화합니다. park()unpark() 와 같은 메소드를 제공합니다.

synchronized 키워드를 사용하고 wait()notify() notifyAll() 메소드를 사용할 수있는 경우 비슷한 작업을 수행 할 수 있습니다.

나는 이것들 중 어느 것이 실제로 더 낫고 왜 그런지 궁금하다.




버트 에프 (Bert F)의 답변 위에 몇 가지 더 추가하고 싶습니다.

Locks 은 암시 적 모니터 ( synchronized 잠금)보다 표현력이 풍부한보다 세분화 된 잠금 제어를위한 다양한 방법을 지원합니다.

잠금은 공유 리소스에 대한 독점적 인 액세스를 제공합니다. 한 번에 하나의 스레드 만 잠금을 획득 할 수 있으며 공유 리소스에 대한 모든 액세스는 먼저 잠금을 획득해야합니다. 그러나 일부 잠금은 ReadWriteLock의 읽기 잠금과 같은 공유 자원에 대한 동시 액세스를 허용 할 수 있습니다.

문서 Lock 에서 동기화통한 잠금 기능의 장점

  1. 동기화 된 메소드 또는 명령문을 사용하면 모든 객체와 관련된 암시 적 모니터 잠금에 대한 액세스가 제공되지만 모든 잠금 획득 및 해제가 블록 구조로 수행되도록합니다

  2. 잠금 구현은 잠금을 획득하기위한 비 차단 시도 lock (tryLock()) , 중단 될 수있는 잠금을 획득하려는 시도 ( lockInterruptibly() 및 획득 시도)를 제공하여 동기화 된 메소드 및 명령문을 사용하는 것보다 추가 기능을 제공합니다 timeout (tryLock(long, TimeUnit)) 할 수있는 락 timeout (tryLock(long, TimeUnit))

  3. Lock 클래스는 보장 된 순서 지정, 비 재진입 사용 또는 교착 상태 감지 와 같이 암시 적 모니터 잠금과는 완전히 다른 동작 및 의미를 제공 할 수도 있습니다.

ReentrantLock : 내 이해에 따라 간단히 말하자면, ReentrantLock 은 객체가 하나의 중요 섹션에서 다른 중요한 섹션으로 ReentrantLock 할 수있게합니다. 하나의 중요 섹션을 입력하기 위해 이미 잠금을 설정 했으므로 현재 잠금을 사용하여 동일한 오브젝트에 대한 다른 중요 섹션을 작성할 수 있습니다.

article ReentrantLock 주요 기능

  1. 방해받지 않고 잠글 수있는 능력.
  2. 자물쇠를 기다리는 동안 타임 아웃하는 기능.
  3. 공정한 자물쇠를 만드는 힘.
  4. 잠금 대기중인 스레드 목록을 가져 오는 API.
  5. 차단하지 않고 잠금을 시도 할 수있는 유연성.

ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock 을 사용하여 읽기 및 쓰기 작업에 대한 세부적인 잠금 제어를 추가로 획득 할 수 있습니다.

이 3 개의 ReentrantLocks 외에도 java 8은 하나 더 많은 잠금을 제공합니다.

StampedLock :

Java 8에는 StampedLock이라는 새로운 종류의 잠금 장치가 함께 제공되며 위의 예와 마찬가지로 읽기 및 쓰기 잠금을 지원합니다. ReadWriteLock과 달리 StampedLock의 잠금 메소드는 long 값으로 표시된 스탬프를 반환합니다.

이 우표를 사용하여 자물쇠를 해제하거나 자물쇠가 유효한지 여부를 확인할 수 있습니다. 또한 스탬프 된 잠금은 낙관적 잠금이라고하는 다른 잠금 모드를 지원합니다.

다른 유형의 ReentrantLockStampedLock 잠금 사용에 대해이 article 를 살펴보십시오.




Lock은 프로그래머의 삶을 편하게 해줍니다. 자물쇠로 쉽게 얻을 수있는 몇 가지 상황이 있습니다.

  1. 하나의 메소드를 잠그고 다른 메소드에서 잠금을 해제하십시오.
  2. 두 개의 다른 코드에서 작업하는 두 개의 스레드가 있지만 첫 번째 스레드는 다른 스레드가 동시에 작동하는 동안 더 진행하기 전에 특정 코드를 완료하기 위해 두 번째 스레드에 대한 종속성이 있습니다. 공유 잠금은이 문제를 아주 쉽게 해결할 수 있습니다.
  3. 모니터 구현. 예를 들어 put 및 get 메소드가 여러 스레드에서 실행되는 단순 대기열. 그러나, 당신은 동일한 방법을 서로 겹치기를 원하지 않겠습니까? 또한 넣기와 가져 오는 방법이 중복 될 수는 없습니다. 그런 경우에는 사설 잠금 장치가있어서 인생을 훨씬 쉽게 해줍니다.

동안, 자물쇠 및 조건은 동기화에 빌드됩니다. 그래서 확실히 그 목표를 달성 할 수 있습니다. 그러나 그것은 당신의 삶을 어렵게 만들고 실제 문제를 푸는 데에서 벗어날 수 있습니다.




synchronized 또는 java.util.concurrent.Lock 을 사용하려는 이유에는 4 가지 주요 요소가 있습니다.

참고 : 동기화 된 잠금은 내재 된 잠금을 말할 때의 의미입니다.

  1. 자바 5가 ReentrantLocks를 가지고 나왔을 때, 그들은 intrinsic locking 이후 주목할만한 처리량 차이를 가지고 있음이 판명되었다. 더 빠른 잠금 장치를 찾고 1.5를 실행중인 경우 jucReentrantLock을 고려하십시오. Java 6의 내장 잠금은 이제 비교할 수 있습니다.

  2. jucLock에는 잠금 메커니즘이 다릅니다. 잠금 인터럽트 가능 - 잠금 스레드가 인터럽트 될 때까지 잠금을 시도합니다. timed lock - 일정 시간 동안 잠금을 시도하고 성공하지 못하면 포기합니다. tryLock - 다른 스레드가 잠금을 유지하고 있으면 잠금을 시도합니다. 이 모든 것은 간단한 자물쇠에서 제외됩니다. 고유 잠금은 단순 잠금 만 제공합니다.

  3. 스타일. 1과 2가 모두 나 자신을 포함하여 대부분의 사람들과 관련된 범주에 속하지 않으면 본질적인 잠금 semenatics가 읽기 쉽고 jucLock 잠금은 덜 자세하게 나타납니다.
  4. 복수 조건. 잠그는 객체는 알림 만 받고 하나의 사례 만 대기합니다. Lock의 newCondition 메소드는 단일 Lock이 기다리거나 신호 할 여러 가지 이유를 가질 수있게합니다. 나는 실제로 실제로이 기능이 필요하지만, 필요한 사람들에게는 좋은 기능입니다.