동기화 및 잠금


182

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

synchronized키워드와 사용 wait()notify() notifyAll()메소드를 사용할 수 있다면 비슷한 일을 할 수 있습니다 .

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


1
유용한 기사가 여기에 : javarevisited.blogspot.in/2013/03/…
roottraveller

답변:


178

단순히 객체를 잠그는 경우 사용하고 싶습니다. synchronized

예:

Lock.acquire();
doSomethingNifty(); // Throws a NPE!
Lock.release(); // Oh noes, we never release the lock!

try{} finally{}어디서나 명시 적으로해야 합니다.

동기화 된 반면에 잘못하는 것은 매우 명확하고 불가능합니다.

synchronized(myObject) {
    doSomethingNifty();
}

즉, Locks는 그러한 깨끗한 방식으로 획득하고 풀 수없는 더 복잡한 것들에 더 유용 할 수 있습니다. 솔직히 맨손으로 사용하는 것을 피하고 Locka CyclicBarrier또는 a 와 같은보다 정교한 동시성 제어를 사용하는 것이 LinkedBlockingQueue좋습니다.

내가 사용하는 이유가 없었습니다 wait()또는 notify()하지만 좋은 것들이있을 수 있습니다.


1
잠금 지원의 대기 / 알림과 파크 / 파크 해제의 차이점은 무엇입니까? docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/…
Pacerier

6
처음에 예제는 잠금과 관련이 있지만, try try 블록을 사용하면 잠금이 해제되지 않은 상태
William Reed

Ahh ... C ++의 RAII 모델에 감사하는 순간 중 하나입니다. std::lock_guard
WhiZTiM

67

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

Lock그리고 Condition(및 다른 새 concurrent클래스)는 도구 상자를위한 더 많은 도구 라는 것을 알았습니다 . 나는 오래된 도리 ( synchronized키워드)로 필요한 모든 것을 할 수 있었지만 어떤 상황에서는 사용하기가 어색했습니다. 도구 상자에 고무 망치, 볼펜 해머, 프라이 바 및 네일 펀치와 같은 도구를 더 추가하면 이러한 어색한 상황이 훨씬 간단 해졌습니다. 그러나 오래된 클로 해머는 여전히 그 사용 점유율을 봅니다.

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

===

나는 생각 의 JavaDoc가 사이의 차이를 잘 설명하지 Lock하고 synchronized(강조는 내입니다) :

잠금 구현은 동기화 된 메소드 및 명령문을 사용하여 얻을 수있는 것보다 더 광범위한 잠금 조작을 제공 합니다. 그것들은 보다 유연한 구조화를 허용 하고 , 상당히 다른 속성을 가질 수 있으며, 연관된 여러 개의 Condition 객체를 지원할 수 있습니다 .

...

의 사용 동기화 방법 이나 문은 모든 객체와 관련된 암묵의 감시 락에의 액세스를 제공하지만, 힘 모든 잠금 획득 및 해제는 블록 구조 방식으로 발생하는 다음과 같은 경우 여러 잠금이 되어 인수반대 순서로 발표해야 하고, 모든 잠금은 잠금을 획득 한 것과 동일한 어휘 범위에서 해제해야합니다 .

동기화 된 메소드 및 명령문 의 범위 지정 메커니즘을 사용하면 모니터 잠금을 사용하여 프로그래밍하는 것이 훨씬 쉬워지고 잠금관련된 많은 일반적인 프로그래밍 오류를 피할 수 있지만보다 유연한 방식으로 잠금으로 작업해야하는 경우가 있습니다. 예를 들어, * 동시에 액세스되는 데이터 구조를 순회하기위한 * 일부 알고리즘 * 은 "Hand-over-hand"또는 "chain locking"을 사용해야합니다. 노드 A, 노드 B의 잠금을 획득 한 다음 A를 해제하고 C를 획득합니다. 그런 다음 B를 놓고 D 등을 얻습니다. 의 구현 잠금 인터페이스는 이런 종류의 테크닉을 이용할 수있게 다른 스코프 내에서 락을 취득 및 해제 할 수 있도록 하고,여러 개의 잠금 장치를 임의의 순서로 획득 및 해제 할 수 있습니다 .

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

...

잠금 및 잠금 해제가 다른 범위에서 발생 ,주의가주의해야 보장 이 유지되는 잠금이 동시에 실행되는 모든 코드 마지막으로-시도에 의해 보호 또는 시도 - 캐치되어 하는 잠금이 해제되어 있는지 확인합니다 필요한 경우.

잠금 구현은 제공하는 추가 기능 제공하여 동기화 방법 및 문장의 사용에를 취득하는 비 차단 시도 잠금을 (설정된 tryLock ()), 시도 중단 될 수있는 잠금 획득 lockInterruptibly을 (() 및 시도 획득 제한 시간을 초과 할 수있는 잠금 (tryLock (long, TimeUnit))

...


23

당신의 유틸리티 모든 것을 달성 할 수있는 java.util.concurrent의이 같은 낮은 수준의 프리미티브와 함께 할을 synchronized, volatile또는 대기 / 통지

그러나 동시성은 까다 롭고 대부분의 사람들은 적어도 일부가 잘못되어 코드가 잘못되었거나 비효율적입니다 (또는 둘 다).

동시 API는 고급 접근 방식을 제공하므로 사용하기가 더 쉽고 안전합니다. 간단히 말해 synchronized, volatile, wait, notify더 이상 직접 사용할 필요가 없습니다.

잠금 자체가이 도구 상자의 낮은 수준의 측면에 클래스, 당신도 (당신이 사용할 수있는 바로 그 중 하나를 사용하지 않아도 Queues세마포 등 물건, 대부분의 시간을).


2
일반 이전 대기 / 알림이 java.util.concurrent.locks.LockSupport의 park / unpark보다 하위 레벨 기본으로 간주됩니까, 아니면 다른 방법입니까?
Pacerier

@Pacerier : 나는 둘 다 저수준 (즉, 응용 프로그램 프로그래머가 직접 사용하지 않으려는 것)이라고 생각하지만, 확실히 java.util.concurrency의 하위 부분 (예 : locks package)은 맨 위에 구축됩니다. 기본 JVM 기본 요소 중 대기 / 알림 (더 낮은 레벨)
Thilo

2
아니오 : 3 : Thread.sleep / interrupt, Object.wait / notify, LockSupport.park / unpark 중 가장 원시적 인 의미는 무엇입니까?
Pacerier

2
@Thilo java.util.concurrent언어 기능 ( synchronized등) 보다 [일반적으로] 더 쉬운 문장을 어떻게 지원하는지 잘 모르겠습니다 . 사용할 때는 코드를 작성하기 전에 java.util.concurrent완료하는 습관을들이는 lock.lock(); try { ... } finally { lock.unlock() }반면 synchronized기본적으로는 처음부터 괜찮습니다. 이 기초만으로 나는 synchronized(행동을 원한다면)보다 쉽다고 말할 것이다 java.util.concurrent.locks.Lock. 파 4
Iwan Aucamp

1
java.util.concurrent 이전에는 사용할 수없는 기본 CAS 호출에 의존하므로 동시성 기본 요소만으로 AtomicXXX 클래스의 동작을 정확하게 복제 할 수 있다고 생각하지 마십시오.
던컨 암스트롱

15

사용하려는 이유에 4 개 가지 주요 요소가있다 synchronized거나 java.util.concurrent.Lock.

참고 : 동기화 잠금은 본질적 잠금을 말할 때 의미합니다.

  1. Java 5가 ReentrantLocks와 함께 나왔을 때, 고유 잠금과는 상당히 다른 처리량 차이가 있음이 증명되었습니다. 더 빠른 잠금 메커니즘을 찾고 1.5를 실행중인 경우 jucReentrantLock을 고려하십시오. Java 6의 고유 잠금 기능은 이제 비슷합니다.

  2. jucLock에는 잠금 메커니즘이 다릅니다. 잠금 인터럽트 가능-잠금 스레드가 중단 될 때까지 잠금을 시도하십시오. 시간 제한 잠금-일정 시간 동안 잠금을 시도하고 성공하지 못하면 포기합니다. tryLock-다른 스레드가 잠금을 잡고 있으면 잠금을 시도합니다. 이 모든 것은 간단한 자물쇠와 함께 포함되어 있습니다. 본질 잠금은 단순한 잠금 만 제공합니다

  3. 스타일. 1과 2가 모두 나 자신을 포함하여 대부분의 사람들과 관련이있는 범주에 속하지 않으면 본질적 잠금 의미 체계가 읽기 쉽고 덜 간결한 jucLock 잠금을 찾을 수 있습니다.
  4. 여러 조건. 잠근 개체는 알림을 받고 단일 사례 만 기다릴 수 있습니다. Lock의 newCondition 메서드를 사용하면 단일 Lock이 여러 가지 이유로 대기하거나 신호를 보낼 수 있습니다. 실제로 실제로는이 기능이 실제로 필요하지는 않지만 필요한 사람들에게는 유용한 기능입니다.

나는 당신의 의견에 대한 세부 사항을 좋아했다. 글 머리 기호를 하나 더 추가합니다. ReadWriteLock은 여러 스레드를 처리하는 경우 유용한 동작을 제공하며 일부 스레드 만 객체에 쓸 필요가 있습니다. 여러 스레드가 동시에 개체를 읽을 수 있으며 다른 스레드가 이미 쓰고있는 경우에만 차단됩니다.
Sam Goldberg

5

Bert F 답변 위에 더 많은 것을 추가하고 싶습니다 .

Locks암시 적 모니터 ( synchronized자물쇠) 보다 더 세밀한 세밀한 잠금 제어를위한 다양한 방법 지원

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

설명서 페이지 에서 동기화 잠금의 장점

  1. 동기화 된 메소드 또는 명령문을 사용하면 모든 오브젝트와 연관된 내재 된 모니터 잠금에 액세스 할 수 있지만 모든 잠금 획득 및 해제는 블록 구조 방식으로 발생합니다.

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

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

ReentrantLock : 내 이해에 따라 간단한 용어로, ReentrantLock하나의 중요한 섹션에서 다른 중요한 섹션으로 객체를 다시 입력 할 수 있습니다. 하나의 중요한 섹션을 입력 할 수있는 잠금이 이미 있으므로 현재 잠금을 사용하여 동일한 객체에 다른 중요한 섹션을 추가 할 수 있습니다.

ReentrantLock기사에 따른 주요 기능

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

ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock읽기 및 쓰기 작업에서 세분화 된 잠금에 대한 제어를 추가로 획득 하는 데 사용할 수 있습니다 .

이 세 가지 ReentrantLock 외에도 Java 8은 하나 이상의 잠금을 제공합니다.

StampedLock :

Java 8에는 위의 예와 같이 읽기 및 쓰기 잠금도 지원하는 StampedLock이라는 새로운 종류의 잠금이 제공됩니다. ReadWriteLock과 달리 StampedLock의 잠금 방법은 long 값으로 표시된 스탬프를 반환합니다.

이 스탬프를 사용하여 잠금을 해제하거나 잠금이 여전히 유효한지 확인할 수 있습니다. 또한 스탬프 잠금은 낙관적 잠금이라는 다른 잠금 모드를 지원합니다.

다른 유형 및 잠금 사용법에 대한 이 기사 를 살펴보십시오 .ReentrantLockStampedLock


4

가장 큰 차이점은 공정성입니다. 즉, 요청이 FIFO를 처리합니까, 아니면 참여할 수 있습니까? 메소드 레벨 동기화는 잠금의 페어 또는 FIFO 할당을 보장합니다. 사용

synchronized(foo) {
}

또는

lock.acquire(); .....lock.release();

공정성을 보장하지 않습니다.

잠금에 대해 많은 경합이있는 경우 새로운 요청이 잠금을 받고 이전 요청이 중단되는 위치에서 쉽게 참여할 수 있습니다. 잠금을 위해 200 개의 스레드가 짧은 순서로 도착하고 두 번째 스레드가 마지막으로 처리되는 경우를 보았습니다. 일부 응용 프로그램에는 문제가 없지만 다른 응용 프로그램에는 치명적입니다.

이 주제에 대한 자세한 내용은 Brian Goetz의 "실제 Java 동시성"책, 13.3 절을 참조하십시오.


5
"방법 수준 동기화는 잠금의 공정한 또는 FIFO 할당을 보장합니다." => 정말? 동기화 된 메소드가 메소드 컨텐츠를 동기화 된 {} 블록으로 래핑하는 것과 다르게 WRT 공정성이 다르게 작동한다고 말하고 있습니까? 나는 그렇게 생각하지 않을 것입니다, 또는 그 문장을 잘못 이해했는지 ...?
weiresr

그렇습니다. 놀랍고 반 직관적 인 것이 맞지만. Goetz의 책이 가장 잘 설명되어 있습니다.
Brian Tarbox

@BrianTarbox가 제공 한 코드를 보면 동기화 된 블록은 "this"이외의 다른 객체를 사용하여 잠급니다. 이론적으로, 블록이 "this"를 잠금으로 사용하는 한, 동기화 된 방법과 상기 방법의 전체 본문을 동기화 된 블록 안에 넣는 것 사이에는 차이가 없습니다.
xburgos

답변은 인용문을 포함하도록 편집되어야하며, 여기에 "통계"가 "통계적 보장"이며 결정적이지 않다는 것을 명확히해야합니다.
Nathan Hughes

죄송합니다. 방금 며칠 전에이 답변에 실수로 투표를 한 적이 있음을 발견했습니다 (서투른 클릭). 불행히도 현재는 되돌릴 수 없습니다. 나중에 고칠 수 있기를 바랍니다.
Mikko Östlund

3

Brian Goetz의 "Java Concurrency In Practice"책, 섹션 13.3 : "... 기본 ReentrantLock과 마찬가지로 내장 잠금은 결정 론적 공정성을 보장하지 않지만 대부분의 잠금 구현에 대한 통계적 공정성 보장은 거의 모든 상황에 충분합니다 ..."


2

잠금은 프로그래머의 삶을 더 쉽게 만듭니다. 잠금으로 쉽게 달성 할 수있는 몇 가지 상황이 있습니다.

  1. 한 방법으로 잠그고 다른 방법으로 잠그십시오.
  2. 그러나 두 개의 다른 코드 조각에서 작업하는 두 개의 스레드가있는 경우 첫 번째 스레드의 두 번째 스레드의 특정 코드 조각에 대한 전제 조건이 있습니다 (다른 스레드도 두 번째 스레드의 동일한 코드 조각에서 작동 함) 스레드 동시에). 공유 잠금은이 문제를 아주 쉽게 해결할 수 있습니다.
  3. 모니터 구현. 예를 들어 put 및 get 메소드가 다른 많은 스레드에서 실행되는 단순 큐입니다. 그러나 여러 put (또는 get) 메소드가 동시에 실행되는 것을 원하지 않으며 put 및 get 메소드가 동시에 실행되는 것을 원하지 않습니다. 개인 잠금 장치를 사용하면 인생을 훨씬 쉽게 달성 할 수 있습니다.

잠금 및 조건은 동기화 된 메커니즘을 기반으로합니다. 따라서 잠금을 사용하여 얻을 수있는 것과 동일한 기능을 확실히 달성 할 수 있습니다. 그러나 동기화 된 복잡한 시나리오를 해결하면 삶이 어려워지고 실제 문제를 해결하지 못할 수 있습니다.


1

잠금과 동기화의 주요 차이점 :

  • 잠금 장치를 사용하면 잠금을 해제하고 원하는 순서로 획득 할 수 있습니다.
  • 동기화 된 상태에서는 잠금을 획득 한 순서 대로만 해제 할 수 있습니다.

0

잠금 및 동기화 블록은 모두 동일한 용도로 사용되지만 사용법에 따라 다릅니다. 아래 부분을 고려하십시오

void randomFunction(){
.
.
.
synchronize(this){
//do some functionality
}

.
.
.
synchronize(this)
{
// do some functionality
}


} // end of randomFunction

위의 경우 스레드가 동기화 블록에 들어가면 다른 블록도 잠 깁니다. 동일한 객체에 이러한 동기화 블록이 여러 개 있으면 모든 블록이 잠 깁니다. 이러한 상황에서 java.util.concurrent.Lock을 사용하여 원하지 않는 블록 잠금을 방지 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.