Programing

동기화 및 잠금

crosscheck 2020. 5. 25. 21:01
반응형

동기화 및 잠금


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

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

이 중 어느 것이 실제로 더 나은지 궁금합니다. 왜 그렇습니까?


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

예:

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

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

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

synchronized(myObject) {
    doSomethingNifty();
}

즉, Locks는 깔끔한 방식으로 획득하고 풀 수없는 더 복잡한 작업에 더 유용 할 수 있습니다. 솔직히 맨손으로 사용하는 것을 피하고 필요에 Lock따라 a CyclicBarrier또는 a 와 같은보다 정교한 동시성 제어를 사용하는 것이 LinkedBlockingQueue좋습니다.

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


이 중 어느 것이 실제로 더 나은지 궁금합니다. 왜 그렇습니까?

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))

...


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

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

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

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


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

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

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

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

  3. Style. If both 1 and 2 do not fall into categories of what you are concerned with most people, including myself, would find the intrinsic locking semenatics easier to read and less verbose then j.u.c.Lock locking.
  4. Multiple Conditions. An object you lock on can only be notified and waited for a single case. Lock's newCondition method allows for a single Lock to have mutliple reasons to await or signal. I have yet to actually need this functionality in practice, but is a nice feature for those who need it.

I would like to add some more things on top of Bert F answer.

Locks support various methods for finer grained lock control, which are more expressive than implicit monitors (synchronized locks)

A Lock provides exclusive access to a shared resource: only one thread at a time can acquire the lock and all access to the shared resource requires that the lock be acquired first. However, some locks may allow concurrent access to a shared resource, such as the read lock of a ReadWriteLock.

Advantages of Lock over Synchronization from documentation page

  1. The use of synchronized methods or statements provides access to the implicit monitor lock associated with every object, but forces all lock acquisition and release to occur in a block-structured way

  2. Lock implementations provide additional functionality over the use of synchronized methods and statements by providing a non-blocking attempt to acquire a lock (tryLock()), an attempt to acquire the lock that can be interrupted (lockInterruptibly(), and an attempt to acquire the lock that can timeout (tryLock(long, TimeUnit)).

  3. A Lock class can also provide behavior and semantics that is quite different from that of the implicit monitor lock, such as guaranteed ordering, non-reentrant usage, or deadlock detection

ReentrantLock: In simple terms as per my understanding, ReentrantLock allows an object to re-enter from one critical section to other critical section . Since you already have lock to enter one critical section, you can other critical section on same object by using current lock.

ReentrantLock key features as per this article

  1. Ability to lock interruptibly.
  2. Ability to timeout while waiting for lock.
  3. Power to create fair lock.
  4. API to get list of waiting thread for lock.
  5. Flexibility to try for lock without blocking.

You can use ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock to further acquire control on granular locking on read and write operations.

Apart from these three ReentrantLocks, java 8 provides one more Lock

StampedLock:

Java 8 ships with a new kind of lock called StampedLock which also support read and write locks just like in the example above. In contrast to ReadWriteLock the locking methods of a StampedLock return a stamp represented by a long value.

You can use these stamps to either release a lock or to check if the lock is still valid. Additionally stamped locks support another lock mode called optimistic locking.

Have a look at this article on usage of different type of ReentrantLock and StampedLock locks.


The main difference is fairness, in other words are requests handled FIFO or can there be barging? Method level synchronization ensures fair or FIFO allocation of the lock. Using

synchronized(foo) {
}

or

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

does not assure fairness.

If you have lots of contention for the lock you can easily encounter barging where newer requests get the lock and older requests get stuck. I've seen cases where 200 threads arrive in short order for a lock and the 2nd one to arrive got processed last. This is ok for some applications but for others it's deadly.

See Brian Goetz's "Java Concurrency In Practice" book, section 13.3 for a full discussion of this topic.


Brian Goetz's "Java Concurrency In Practice" book, section 13.3: "...Like the default ReentrantLock, intrinsic locking offers no deterministic fairness guarantees, but the statistical fairness guarantees of most locking implementations are good enough for almost all situations..."


Lock makes programmers life easier. Here are few situations that can be achieved easier with lock.

  1. Lock in one method, and release the lock in other method.
  2. You have two threads working on two different pieces of code, however first thread there is dependency on there second thread to complete certain piece of code before it proceed any further (while some other threads also working simultaneously). A shared lock can solve this problem quite easily.
  3. Implementing monitors. For example, a simple queue where the put and get methods are executed from many different threads. However, do you want to over lap neither the same methods one on another, nor both put and get methods can overlap. In such case a private lock makes the life very easier.

While, the lock, and conditions are build on the synchronized. So certainly you can achiever the same goal with that. However, that might make your life difficult and can deviate you from solving the actual problem.


Major difference between lock and synchronized:

  • with locks, you can release and acquire the locks in any order.
  • with synchronized, you can release the locks only in the order it was acquired.

Lock and synchronize block both serves the same purpose but it depends on the usage. Consider the below part

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

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


} // end of randomFunction

In the above case , if a thread enters the synchronize block, the other block is also locked. If there are multiple such synchronize block on the same object, all the blocks are locked. In such situations , java.util.concurrent.Lock can be used to prevent unwanted locking of blocks

참고URL : https://stackoverflow.com/questions/4201713/synchronization-vs-lock

반응형