Java 중요 섹션에서 무엇을 동기화해야합니까?
Java에서 코드에서 중요 섹션을 선언하는 관용적 방법은 다음과 같습니다.
private void doSomething() {
// thread-safe code
synchronized(this) {
// thread-unsafe code
}
// thread-safe code
}
거의 모든 블록이에서 동기화 this
되지만 특별한 이유가 있습니까? 다른 가능성이 있습니까? 동기화 할 개체에 대한 모범 사례가 있습니까? (예 : Object
?의 개인 인스턴스 )
먼저 다음 코드 스 니펫이 동일합니다.
public void foo() {
synchronized (this) {
// do something thread-safe
}
}
과:
public synchronized void foo() {
// do something thread-safe
}
이렇게 정확히 같은 일을 . 코드 가독성과 스타일을 제외하고는 둘 중 하나를 선호하지 않습니다.
메서드 또는 코드 블록을 동기화 할 때 이러한 작업을 수행하는 이유 와 정확히 어떤 객체 를 잠그고 있는지 , 어떤 용도 로 사용 하는지 아는 것이 중요합니다 .
또한 다음 예제와 같이 요청하는 모니터 (즉, 동기화 된 객체)가 반드시 필요하지 않은 클라이언트 측 코드 블록을 동기화 하려는 상황 this
이 있습니다.
Vector v = getSomeGlobalVector();
synchronized (v) {
// some thread-safe operation on the vector
}
동시 프로그래밍에 대한 더 많은 지식을 얻는 것이 좋습니다. 장면 뒤에서 무슨 일이 일어나고 있는지 정확히 알면 많은 도움이 될 것입니다. 이 주제에 대한 훌륭한 책인 Concurrent Programming in Java를 확인해야합니다 . 주제에 대해 빠르게 알아보고 싶다면 Java Concurrency @ Sun을 확인하십시오.
이전 응답자가 언급했듯이 제한된 범위의 개체에서 동기화하는 것이 가장 좋습니다 (즉, 벗어날 수있는 가장 제한적인 범위를 선택하고 사용합니다.). 특히, 동기화하는 this
것은 좋지 않은 생각입니다. 클래스의 사용자가 잠금을 얻도록 허용하려고합니다.
그러나 .NET에서 동기화하도록 선택하면 특히 추악한 경우가 발생합니다 java.lang.String
. 문자열은 인턴 될 수 있습니다 (실제로 거의 항상). 즉, 동일한 콘텐츠의 각 문자열 ( 전체 JVM 에서)은 배후에서 동일한 문자열로 판명됩니다. 즉, 임의의 문자열에서 동기화하는 경우 동일한 내용을 가진 문자열을 잠그는 다른 (완전히 다른) 코드 섹션도 실제로 코드를 잠급니다.
나는 한때 프로덕션 시스템의 교착 상태를 해결하고 있었고 (매우 고통스럽게) 내용이 둘 다 인 String 인스턴스에서 각각 동기화되는 완전히 다른 두 개의 오픈 소스 패키지에 대한 교착 상태를 추적했습니다 "LOCK"
.
동기화를 피하려고하면 this
해당 개체에 대한 참조가있는 외부의 모든 사람이 내 동기화를 차단할 수 있기 때문입니다. 대신 로컬 동기화 개체를 만듭니다.
public class Foo {
private final Object syncObject = new Object();
…
}
이제 누군가가 잠금을 "훔치는"것에 대한 두려움없이 동기화에 해당 개체를 사용할 수 있습니다.
Java에서 사용 가능한 ReadWriteLocks도 있음을 강조하기 위해 java.util.concurrent.locks.ReadWriteLock으로 발견됩니다.
대부분의 사용에서 '읽기 용'과 '업데이트 용'으로 잠금을 분리합니다. 단순히 동기화 된 키워드를 사용하는 경우 동일한 메서드 / 코드 블록에 대한 모든 읽기가 '대기열'됩니다. 한 번에 하나의 스레드 만 블록에 액세스 할 수 있습니다.
대부분의 경우 단순히 읽기만하는 경우 동시성 문제에 대해 걱정할 필요가 없습니다. 쓰기를 할 때 동시 업데이트 (데이터 손실)에 대해 걱정하거나 쓰기 중 읽기 (부분 업데이트)에 대해 걱정해야합니다.
따라서 다중 스레드 프로그래밍 중에 읽기 / 쓰기 잠금이 더 의미가 있습니다.
뮤텍스 역할을 할 수있는 오브젝트에서 동기화하고 싶을 것입니다. 현재 인스턴스 ( 이 참조)가 적합한 경우 (예를 들어 Singleton이 아님) Java에서 모든 객체가 Mutex 역할을 할 수 있으므로이를 사용할 수 있습니다.
다른 경우에 이러한 클래스의 인스턴스가 모두 동일한 리소스에 액세스해야하는 경우 여러 클래스간에 Mutex를 공유 할 수 있습니다.
작업중인 환경과 구축중인 시스템 유형에 따라 다릅니다. 내가 본 대부분의 Java EE 애플리케이션에서는 실제로 동기화가 실제로 필요하지 않습니다.
개인적으로 동기화하는 것이 결코 정확하지 않거나 거의 정확하지 않다고 주장하는 대답 this
은 잘못된 것이라고 생각합니다. API에 달려 있다고 생각합니다. 클래스가 스레드 세이프 구현이고이를 문서화하는 경우 this
. 동기화가 클래스의 각 인스턴스를 공용 메서드 호출에서 전체 스레드로부터 안전하게 만드는 것이 아니라면 개인 내부 개체를 사용해야합니다. 재사용 가능한 라이브러리 구성 요소는 종종 이전 범주에 속합니다. 사용자가 외부 동기화에서 API를 래핑하는 것을 허용하지 않기 전에 신중하게 생각해야합니다.
전자의 경우 using을 사용 this
하면 원자 방식으로 여러 메서드를 호출 할 수 있습니다. 한 가지 예는 PrintWriter입니다. 여기에서 여러 줄 (예 : 콘솔 / 로거에 대한 스택 추적)을 출력하고 함께 표시되도록 보장 할 수 있습니다.이 경우 동기화 개체를 내부적으로 숨기는 것은 정말 고통스러운 일입니다. 이러한 또 다른 예는 동기화 된 컬렉션 래퍼입니다. 반복하려면 컬렉션 개체 자체에서 동기화해야합니다. 반복은 여러 메서드 호출로 구성되므로 내부적으로 완전히 보호 할 수 없습니다 .
후자의 경우 일반 객체를 사용합니다.
private Object mutex=new Object();
그러나 잠금이 "java.lang.Object ()의 인스턴스"라고 말하는 많은 JVM 덤프 및 스택 추적을 보았으므로 다른 사람들이 제안한 것처럼 내부 클래스를 사용하는 것이 종종 더 도움이 될 수 있다고 말해야합니다.
어쨌든, 그것은 내 두 비트 가치입니다.
편집 : 다른 하나는 동기화 할 때 this
방법을 동기화하고 방법을 매우 세분화하는 것을 선호합니다. 더 명확하고 간결하다고 생각합니다.
Java의 동기화에는 종종 동일한 인스턴스에 대한 작업 동기화가 포함됩니다. 동기화 는 클래스의 다른 인스턴스 메서드 (또는 섹션)간에 자동으로 사용할 수있는 공유 참조 this
이므로 매우 관용적 this
입니다.
Using another reference specifically for locking, by declaring and initializing a private field Object lock = new Object()
for example, is something I never needed or used. I think it is only useful when you need external synchronization on two or more unsynchronized resources inside an object, although I would always try to refactor such a situation into a simpler form.
Anyway, implicit (synchronized method) or explicit synchronized(this)
is used a lot, also in the Java libraries. It is a good idiom and, if applicable, should always be your first choice.
On what you synchronize depends on what other threads that might potentially get into conflict with this method call can synchronize.
If this
is an object that is used by only one thread and we are accessing a mutable object which is shared between threads, a good candidate is to synchronize over that object - synchronizing on this
has no point since another thread that modifies that shared object might not even know this
, but does know that object.
On the other hand synchronizing over this
makes sense if many threads call methods of this object at the same time, for instance if we are in a singleton.
Note that a syncronized method is often not the best option, since we hold a lock the whole time the method runs. If it contains timeconsuming but thread safe parts, and a not so time consuming thread-unsafe part, synchronizing over the method is very wrong.
Almost all blocks synchronize on this, but is there a particular reason for this? Are there other possibilities?
This declaration synchronizes entire method.
private synchronized void doSomething() {
This declaration synchronized a part of code block instead of entire method.
private void doSomething() {
// thread-safe code
synchronized(this) {
// thread-unsafe code
}
// thread-safe code
}
From oracle documentation page
making these methods synchronized has two effects:
First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
Are there other possibilities? Are there any best practices on what object to synchronize on? (such as private instances of Object?)
There are many possibilities and alternatives to synchronization. You can make your code thread safe by using high level concurrency APIs( available since JDK 1.5 release)
Lock objects
Executors
Concurrent collections
Atomic variables
ThreadLocalRandom
Refer to below SE questions for more details:
Avoid synchronized(this) in Java?
the Best Practices is to create an object solely to provide the lock:
private final Object lock = new Object();
private void doSomething() {
// thread-safe code
synchronized(lock) {
// thread-unsafe code
}
// thread-safe code
}
By doing this you are safe, that no calling code can ever deadlock your method by an unintentional synchronized(yourObject)
line.
(Credits to @jared and @yuval-adam who explained this in more details above.)
My guess is that the popularity of using this
in tutorials came from early Sun javadoc: https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
참고URL : https://stackoverflow.com/questions/416183/in-java-critical-sections-what-should-i-synchronize-on
'Nice programing' 카테고리의 다른 글
@ Html.DisplayFor-DateFormat ( "mm / dd / yyyy") (0) | 2020.10.31 |
---|---|
Android Studio 드로어 블 폴더 (0) | 2020.10.31 |
@로 매개 변수 이름 접두사 C # (0) | 2020.10.31 |
Android의 WebView에서 JavaScript에서 반환 값을 얻는 방법은 무엇입니까? (0) | 2020.10.31 |
무한 스크롤 jquery 플러그인 (0) | 2020.10.31 |