Synchronized Block 대신 Synchronized Method를 사용하는 장점이 있습니까?
예를 들어 동기화된 블록에 비해 동기화된 방법의 장점을 가르쳐 주실 수 있습니까?
예를 들어 동기화된 블록에 비해 동기화된 방식의 장점을 말씀해 주실 수 있습니까?고마워요.
블록에 비해 동기화된 방식을 사용하는 것은 명확한 이점이 없습니다.
한 것는 할 수 참조를 포함할입니다.this
.
방법:
public synchronized void method() { // blocks "this" from here....
...
...
...
} // to here
블록:
public void method() {
synchronized( this ) { // blocks "this" from here ....
....
....
....
} // to here...
}
봐, 전혀 이득이 없어
블록은 메서드보다 장점이 있습니다.메서드를 동기화하면 오브젝트 전체가 잠기는 반면 다른 오브젝트를 잠금으로 사용할 수 있기 때문에 대부분 유연성이 있습니다.
비교:
// locks the whole object
...
private synchronized void someInputRelatedWork() {
...
}
private synchronized void someOutputRelatedWork() {
...
}
대.
// Using specific locks
Object inputLock = new Object();
Object outputLock = new Object();
private void someInputRelatedWork() {
synchronized(inputLock) {
...
}
}
private void someOutputRelatedWork() {
synchronized(outputLock) {
...
}
}
또한 메서드가 증가하더라도 동기화된 섹션을 분리하여 유지할 수 있습니다.
private void method() {
... code here
... code here
... code here
synchronized( lock ) {
... very few lines of code here
}
... code here
... code here
... code here
... code here
}
유일한 실제 차이점은 동기화된 블록이 동기화된 객체를 선택할 수 있다는 것입니다.에서는 사용할 수 것은 「」입니다.'this'
(또는 동기 클래스 메서드의 대응하는 클래스인스턴스).예를 들어, 이것들은 의미상 동등합니다.
synchronized void foo() {
...
}
void foo() {
synchronized (this) {
...
}
}
후자는 오브젝트(종종 멤버 변수)와 관련된 잠금을 경쟁할 수 있기 때문에 더 유연합니다.또한 블록 전후에 동시 코드가 실행될 수 있지만 메서드 내에서 실행될 수 있기 때문에 더 세분화됩니다.물론 동시 코드를 별도의 비동기 방식으로 리팩터링함으로써 동기화된 방법을 쉽게 사용할 수 있습니다.코드를 이해하기 쉬운 것을 사용합니다.
동기 방식
장점:
- IDE는 동기화된 메서드를 나타낼 수 있습니다.
- 구문은 더 콤팩트합니다.
- 동기화된 블록을 다른 메서드로 강제로 분할합니다.
단점:
- 이와 동기화되므로 외부인들도 이에 동기화할 수 있습니다.
- 동기화된 블록 밖으로 코드를 이동하기가 더 어렵습니다.
동기 블록
장점:
- 잠금에 개인 변수를 사용할 수 있으므로 강제로 클래스 내에 잠금을 유지할 수 있습니다.
- 동기화된 블록은 변수에 대한 참조를 검색하여 찾을 수 있습니다.
단점:
- 구문이 더 복잡하기 때문에 코드를 읽기 어렵습니다.
개인적으로는 동기화가 필요한 것에만 초점을 맞춘 클래스에서 동기화된 메서드를 사용하는 것을 선호합니다.이러한 클래스는 가능한 한 작아야 하며, 따라서 동기화를 검토하기가 쉬워야 합니다.다른 사용자는 동기화에 신경 쓸 필요가 없습니다.
주된 차이점은 동기화된 블록을 사용하는 경우 이 오브젝트 이외의 오브젝트로 잠글 수 있다는 것입니다.이것에 의해, 유연성이 향상됩니다.
메시지 큐와 여러 메시지 생산자와 소비자가 있다고 가정합니다.우리는 생산자들이 서로 간섭하는 것을 원하지 않지만, 소비자들은 생산자들을 기다리지 않고 메시지를 검색할 수 있어야 한다.그래서 우리는 그냥 객체를 만들고
Object writeLock = new Object();
그리고 이제부터는 프로듀서가 새로운 메시지를 추가할 때마다 그 메시지를 고정시킵니다.
synchronized(writeLock){
// do something
}
그래서 소비자들은 여전히 책을 읽을 수 있고, 생산자들은 문을 닫게 될 것이다.
동기 방식
동기화된 메서드는 두 가지 효과가 있습니다.
첫 번째 스레드가 오브젝트에 대해 동기화된 메서드를 실행하고 있는 경우, 첫 번째 스레드가 오브젝트에 대해 완료될 때까지 동일한 오브젝트 블록에 대해 동기화된 메서드를 호출하는 다른 모든 스레드(실행 일시정지)입니다.
둘째, 동기화된 메서드가 종료되면 동일한 오브젝트에 대해 동기화된 메서드의 후속 호출과 open-before 관계를 자동으로 확립한다.이렇게 하면 개체 상태에 대한 변경 내용이 모든 스레드에 표시됩니다.
컨스트럭터는 동기화할 수 없습니다.동기화된 키워드를 컨스트럭터와 함께 사용하면 구문 오류가 발생합니다.개체를 생성하는 스레드만 개체를 생성하는 동안 해당 개체에 액세스할 수 있으므로 생성자를 동기화하는 것은 의미가 없습니다.
동기 스테이트먼트
동기화된 메서드와 달리 동기화된 문은 고유한 잠금을 제공하는 개체를 지정해야 합니다.목록이나 지도에 대한 액세스를 동기화할 때 주로 사용하지만 개체의 모든 메서드에 대한 액세스를 차단하고 싶지는 않습니다.
Q: 본질적인 잠금과 동기화 동기화는 본질적인 잠금 또는 모니터 잠금으로 알려진 내부 엔티티를 중심으로 구축됩니다.(API 사양에서는 이 엔티티를 단순히 "모니터"라고 부릅니다).본질적인 잠금은 동기화 양면에서 역할을 합니다.즉, 오브젝트 상태에 대한 배타적 접근을 강제하고 occurs-bef를 확립합니다.가시성에 필수적인 관계를 구축합니다.
모든 오브젝트에는 고유의 잠금이 관련되어 있습니다.관례상 오브젝트 필드에 대한 배타적이고 일관된 액세스가 필요한 스레드는 오브젝트 필드에 액세스하기 전에 오브젝트의 본질적인 잠금을 취득한 후 오브젝트 필드가 완료되면 본질적인 잠금을 해제해야 합니다.나사산은 잠금을 획득한 후 잠금을 해제할 때까지 고유의 잠금을 소유한다고 합니다.스레드가 고유 잠금을 소유하고 있는 한 다른 스레드는 동일한 잠금을 획득할 수 없습니다.잠금을 획득하려고 하면 다른 스레드가 차단됩니다.
package test;
public class SynchTest implements Runnable {
private int c = 0;
public static void main(String[] args) {
new SynchTest().test();
}
public void test() {
// Create the object with the run() method
Runnable runnable = new SynchTest();
Runnable runnable2 = new SynchTest();
// Create the thread supplying it with the runnable object
Thread thread = new Thread(runnable,"thread-1");
Thread thread2 = new Thread(runnable,"thread-2");
// Here the key point is passing same object, if you pass runnable2 for thread2,
// then its not applicable for synchronization test and that wont give expected
// output Synchronization method means "it is not possible for two invocations
// of synchronized methods on the same object to interleave"
// Start the thread
thread.start();
thread2.start();
}
public synchronized void increment() {
System.out.println("Begin thread " + Thread.currentThread().getName());
System.out.println(this.hashCode() + "Value of C = " + c);
// If we uncomment this for synchronized block, then the result would be different
// synchronized(this) {
for (int i = 0; i < 9999999; i++) {
c += i;
}
// }
System.out.println("End thread " + Thread.currentThread().getName());
}
// public synchronized void decrement() {
// System.out.println("Decrement " + Thread.currentThread().getName());
// }
public int value() {
return c;
}
@Override
public void run() {
this.increment();
}
}
동기화된 메서드, 블록과 동기화되지 않은 출력을 교차 점검합니다.
주의: 정적 동기 메서드 및 블록은 Class 개체에서 작동합니다.
public class MyClass {
// locks MyClass.class
public static synchronized void foo() {
// do something
}
// similar
public static void foo() {
synchronized(MyClass.class) {
// do something
}
}
}
Java 컴파일러는 소스 코드를 바이트 코드로 변환할 때 동기화된 메서드와 동기화된 블록을 매우 다르게 처리합니다.
JVM이 동기화된 메서드를 실행할 때 실행 스레드는 메서드의 method_info 구조에 ACC_SYNCHIZED 플래그가 설정되어 있음을 식별하고 자동으로 오브젝트의 잠금을 취득하여 메서드를 호출하여 잠금을 해제합니다.예외가 발생하면 스레드는 자동으로 잠금을 해제합니다.
반면 메서드 블록을 동기화하면 개체의 잠금 및 예외 처리를 얻기 위한 JVM의 기본 지원 기능이 무시되고 기능이 바이트 코드로 명시적으로 작성되어야 합니다.동기화된 블록이 있는 메서드의 바이트 코드를 읽으면 이 기능을 관리하기 위한 추가 작업이 12개 이상 표시됩니다.
동기화된 메서드와 동기화된 블록을 모두 생성하기 위한 콜을 다음에 나타냅니다.
public class SynchronizationExample {
private int i;
public synchronized int synchronizedMethodGet() {
return i;
}
public int synchronizedBlockGet() {
synchronized( this ) {
return i;
}
}
}
synchronizedMethodGet()
코드를 합니다.
0: aload_0
1: getfield
2: nop
3: iconst_m1
4: ireturn
여기 이 요.synchronizedBlockGet()
★★★★
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: aload_0
5: getfield
6: nop
7: iconst_m1
8: aload_1
9: monitorexit
10: ireturn
11: astore_2
12: aload_1
13: monitorexit
14: aload_2
15: athrow
동기화된 방식과 블록의 중요한 차이점 중 하나는 동기화된 블록이 일반적으로 잠금 범위를 줄여준다는 것입니다.잠금 범위는 성능에 반비례하므로 코드의 중요한 부분만 잠그는 것이 항상 좋습니다.동기화된 블록을 사용하는 가장 좋은 예 중 하나는 전체를 잠그는 대신 싱글톤 패턴으로 잠금을 이중 체크하는 것입니다.getInstance()
method 우리는 싱글톤 인스턴스를 만드는 데 사용되는 코드의 중요한 부분만 잠급니다.따라서 잠금이 1~2회만 필요하므로 성능이 대폭 향상됩니다.
동기 방식을 사용할 때는, 스태틱 동기 방식과 비 스태틱 동기 방식을 혼재시키는 경우는, 특히 주의가 필요합니다.
목록이나 지도에 대한 액세스를 동기화할 때 주로 사용하지만 개체의 모든 메서드에 대한 액세스를 차단하고 싶지는 않습니다.
다음 코드에서는 목록을 수정하는 스레드 하나가 맵을 수정하는 스레드를 기다리는 것을 차단하지 않습니다.오브젝트에서 메서드가 동기화되어 있는 경우 각 메서드는 변경 내용이 경합하지 않아도 대기해야 합니다.
private List<Foo> myList = new ArrayList<Foo>();
private Map<String,Bar) myMap = new HashMap<String,Bar>();
public void put( String s, Bar b ) {
synchronized( myMap ) {
myMap.put( s,b );
// then some thing that may take a while like a database access or RPC or notifying listeners
}
}
public void hasKey( String s, ) {
synchronized( myMap ) {
myMap.hasKey( s );
}
}
public void add( Foo f ) {
synchronized( myList ) {
myList.add( f );
// then some thing that may take a while like a database access or RPC or notifying listeners
}
}
public Thing getMedianFoo() {
Foo med = null;
synchronized( myList ) {
Collections.sort(myList);
med = myList.get(myList.size()/2);
}
return med;
}
동기화된 블록을 사용하면 여러 개의 동기화자를 가질 수 있으므로 동시에 충돌하지 않는 여러 가지 작업을 동시에 진행할 수 있습니다.
동기화된 메서드는 reflection API를 사용하여 확인할 수 있습니다.모델의 모든 메서드가 동기화되는 등 일부 계약을 테스트할 때 유용합니다.
다음 스니펫은 해시 테이블의 동기화된 메서드를 모두 인쇄합니다.
for (Method m : Hashtable.class.getMethods()) {
if (Modifier.isSynchronized(m.getModifiers())) {
System.out.println(m);
}
}
동기화된 블록을 사용할 때 주의: 잠금 개체로 사용할 때 주의하십시오!
위의 user2277816의 코드 스니펫은 문자열 리터럴에 대한 참조가 잠금 개체로 사용되는 점을 나타냅니다.문자열 리터럴은 자동으로 Java에 삽입되므로 문제가 발생합니다. 문자 그대로의 "잠금"에서 동기화하는 모든 코드 조각은 동일한 잠금을 공유합니다.이로 인해 전혀 관련이 없는 코드 조각으로 인해 교착 상태가 쉽게 발생할 수 있습니다.
주의해야 할 것은 String 객체뿐만이 아닙니다.자동 상자와 valueOf 메서드는 값에 따라 동일한 개체를 재사용할 수 있기 때문에 상자형 프리미티브도 위험합니다.
상세한 것에 대하여는, https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reused 를 참조해 주세요.
종종 메서드 수준에서 잠금을 사용하는 것은 너무 무례한 것입니다.공유 리소스에 액세스하지 않는 코드를 전체 메서드를 잠그는 이유는 무엇입니까?각 개체에는 잠금이 있으므로 더미 개체를 생성하여 블록 수준 동기화를 구현할 수 있습니다.블록 레벨은 전체 메서드를 잠그지 않기 때문에 더 효율적입니다.
여기 몇 가지 예가 있습니다.
메서드 레벨
class MethodLevel {
//shared among threads
SharedResource x, y ;
public void synchronized method1() {
//multiple threads can't access
}
public void synchronized method2() {
//multiple threads can't access
}
public void method3() {
//not synchronized
//multiple threads can access
}
}
블록 레벨
class BlockLevel {
//shared among threads
SharedResource x, y ;
//dummy objects for locking
Object xLock = new Object();
Object yLock = new Object();
public void method1() {
synchronized(xLock){
//access x here. thread safe
}
//do something here but don't use SharedResource x, y
// because will not be thread-safe
synchronized(xLock) {
synchronized(yLock) {
//access x,y here. thread safe
}
}
//do something here but don't use SharedResource x, y
//because will not be thread-safe
}//end of method1
}
[편집]
★★★의 Collection
Vector
★★★★★★★★★★★★★★★★★」Hashtable
두 는 일치합니다.ArrayList
★★★★★★★★★★★★★★★★★」HashMap
하거나 Collections 메서드를 .synchronized " " " " " Collections synchronized " " " 。
Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list
유일한 차이점: 동기화된 블록은 동기화된 방식과 달리 세분화된 잠금을 허용합니다.
으로는 ★★★★★★★★★★★★★★.synchronized
블록 또는 메서드는 메모리 불일치 오류를 방지하여 스레드 세이프 코드를 작성하기 위해 사용되었습니다.
이 질문은 매우 오래되었고 지난 7년 동안 많은 것들이 바뀌었다.스레드 안전을 위해 새로운 프로그래밍 구조가 도입되었습니다.
하려면 , 「어드밴스드 API」 에 「 동시성 를합니다.synchronied
블록.이 문서 페이지는 스레드 안전을 실현하기 위한 적절한 프로그래밍 구조를 제공합니다.
Lock Objects는 많은 동시 응용 프로그램을 단순화하는 잠금 숙어를 지원합니다.
실행자는 스레드를 시작하고 관리하기 위한 고급 API를 정의합니다.java.util.concurrent에 의해 제공되는 이그제큐티브 실장은 대규모 애플리케이션에 적합한 스레드 풀 관리를 제공합니다.
동시 수집을 사용하면 대량의 데이터 수집을 보다 쉽게 관리할 수 있으며 동기화 필요성을 크게 줄일 수 있습니다.
원자 변수에는 동기화를 최소화하고 메모리 일관성 오류를 방지하는 기능이 있습니다.
ThreadLocalRandom(JDK 7 내)은 여러 스레드에서 의사 난수를 효율적으로 생성합니다.
동기화에 대한 더 나은 대체 방법은 ReentrantLock입니다. ReentrantLock은Lock
재진입 상호 제외 동기화된 메서드 및 스테이트먼트를 사용하여 액세스하는 암묵적 모니터 잠금과 동일한 기본 동작 및 의미론을 가지지만 확장 기능을 가진 잠금.
잠금 예:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
다른 프로그래밍 구성에 대해서도 java.util.concurrent 및 java.util.concurrent.atomic 패키지를 참조하십시오.
다음의 관련 질문도 참조해 주세요.
동기화된 메서드는 모든 개체를 잠그는 데 사용됩니다. 동기화된 블록은 특정 개체를 잠그는 데 사용됩니다.
일반적으로 사용되는 개체의 모니터에 대해 명시적인 것과 암묵적인 이 개체에 대해 명시적인 것 이외에는 거의 동일합니다.동기화된 메서드의 한 가지 단점은 "this" 참조를 사용하여 동기화할 때 외부 객체가 동일한 객체에서 잠길 가능성을 열어둔다는 것입니다.그것은 매우 미묘한 버그가 될 수 있습니다.내부 명시적 개체 또는 기타 기존 필드에서 동기화하면 이 문제를 방지할 수 있으며, 동기화가 완전히 캡슐화됩니다.
여기에서 이미 설명한 바와 같이 동기화된 함수가 "this"만 사용하는 경우 동기화된 블록은 사용자 정의 변수를 잠금 개체로 사용할 수 있습니다.물론 동기화할 필요가 있는 기능의 영역도 조작할 수 있습니다.그러나 동기화된 함수와 "this"를 잠금 객체로 사용하여 함수 전체를 커버하는 블록의 차이는 없다고 합니다.그렇지 않습니다. 두 가지 상황에서 생성되는 바이트 코드의 차이가 있습니다.동기화된 블록 사용의 경우 "this"를 참조하는 로컬 변수를 할당해야 합니다.그 결과, 기능에 대해서는 조금 큰 사이즈가 됩니다(기능의 수가 적은 경우는 관계가 없습니다).
차이점에 대한 자세한 내용은 http://www.artima.com/insidejvm/ed2/threadsynchP.html를 참조하십시오.
동기화된 메서드의 경우 개체에 대한 잠금이 획득됩니다.그러나 동기화된 블록을 사용할 경우 잠금을 가져올 개체를 지정할 수 있습니다.
예:
Class Example {
String test = "abc";
// lock will be acquired on String test object.
synchronized (test) {
// do something
}
lock will be acquired on Example Object
public synchronized void testMethod() {
// do some thing
}
}
질문인 건 있는 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아,synchronized
메서드가 잘못된 잠금일 수 있습니다.
Java Concurrency In Practice (72년) :
public class ListHelper<E> {
public List<E> list = Collections.syncrhonizedList(new ArrayList<>());
...
public syncrhonized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if(absent) {
list.add(x);
}
return absent;
}
위의 코드는 스레드 세이프인 것처럼 보입니다.그러나 실제로는 그렇지 않다.이 경우 클래스 인스턴스에서 잠금이 취득됩니다.그러나 이 방법을 사용하지 않는 다른 스레드에 의해 목록이 변경될 수 있습니다.올바른 접근법은 다음과 같습니다.
public boolean putIfAbsent(E x) {
synchronized(list) {
boolean absent = !list.contains(x);
if(absent) {
list.add(x);
}
return absent;
}
}
위의 코드는 동기화된 블록이 완료될 때까지 목록을 수정하려는 모든 스레드를 차단합니다.
실제로 동기화된 블록에 비해 동기화된 메서드의 장점은 더 멍청하다는 것입니다.잠글 임의의 오브젝트를 선택할 수 없기 때문에 동기화된 메서드 구문을 오용하여 문자열 리터럴로 잠그거나 변경 가능한 필드의 내용을 잠글 수 없습니다.실타래 밑에서요
반면 동기화된 메서드를 사용하면 개체에 대한 참조를 가져올 수 있는 스레드에 의해 잠금이 획득되지 않도록 보호할 수 없습니다.
따라서 메서드에 대한 수정자로 동기화를 사용하면 카우오커가 다치지 않도록 보호하는 데 효과적이며, 프라이빗 최종 잠금 개체와 함께 동기화된 블록을 사용하면 카우오커로부터 자신의 코드를 보호할 수 있습니다.
Java 사양 개요:http://www.cs.cornell.edu/andru/javaspec/17.doc.html
synchronized 스테이트먼트(θ14.17)는 오브젝트에 대한 참조를 계산한 후 해당 오브젝트에 대해 잠금액션을 실행하려고 하고 잠금액션이 정상적으로 완료될 때까지 처리를 진행하지 않습니다.
동기 방식( (8.4.3.5)은, 기동시에 자동적으로 록 액션을 실행해, 록 액션이 정상적으로 완료될 때까지 본문은 실행되지 않습니다.메서드가 인스턴스 메서드인 경우 메서드 본문 실행 중 호출된 인스턴스와 관련된 잠금(즉, 메서드 본문 실행 중 이렇게 인식되는 개체)을 잠급니다.메서드가 스태틱한 경우 메서드가 정의되어 있는 클래스를 나타내는 Class 객체와 관련된 잠금을 잠급니다. ...
이러한 설명에 근거해, 대부분의 앞의 답변이 올바르고, 동기화된 메서드는 정적 메서드에 특히 도움이 될 수 있습니다.그렇지 않으면 "메서드가 정의된 클래스를 나타내는 클래스 오브젝트"를 취득하는 방법을 알아내야 합니다.
편집: 원래는 Java의 실제 사양에 대한 견적인 줄 알았습니다.이 페이지는 사양의 개요/설명일 뿐임을 명확히 했다.
TLDR, 둘 다 사용 안 함synchronized
"수식자",synchronized(this){...}
but ( 은 express express express 。synchronized(myLock){...}
서 ''는myLock
는 프라이빗 오브젝트를 저장하는 최종 인스턴스 필드입니다.
「 」를 synchronized
및 「」의 수식자.synchronized(..){ }
메서드 본문의 표현은 다음과 같습니다.
synchronized
메서드 시그니처에 지정된 수식자synchronized(...){...}
expression(식)- 메서드 본문의 일부 실행만 동기화하려면
- 컨스트럭터 또는 (정적) 초기화 블록 내에서 사용되는 경우,
- 동기 액세스를 제어하는 잠금 개체를 선택합니다.
을 synchronized
또는 「」synchronized(...) {...}
this
로서(「」의 와 같이)synchronized(this) {...}
)도 같은 단점이 있습니다.둘 다 동기화하기 위한 잠금 개체로 자체 인스턴스를 사용합니다.이는 객체 자체뿐만 아니라 해당 객체에 대한 참조를 보유하고 있는 다른 외부 객체/코드도 동기화 잠금으로 사용할 수 있으며 심각한 부작용(성능 저하 및 교착 상태)이 발생할 수 있기 때문에 위험합니다.
는 '사용하지 것'입니다.synchronized
"수식자",synchronized(...)
「 」와 this
잠금 개체로 지정되지만 이 개체에 대한 전용 잠금 개체로 지정됩니다.예를 들어 다음과 같습니다.
public class MyService {
private final lock = new Object();
public void doThis() {
synchronized(lock) {
// do code that requires synchronous execution
}
}
public void doThat() {
synchronized(lock) {
// do code that requires synchronous execution
}
}
}
여러 잠금 개체를 사용할 수도 있지만 중첩을 사용할 때 교착 상태가 발생하지 않도록 각별히 주의해야 합니다.
public class MyService {
private final lock1 = new Object();
private final lock2 = new Object();
public void doThis() {
synchronized(lock1) {
synchronized(lock2) {
// code here is guaranteed not to be executes at the same time
// as the synchronized code in doThat() and doMore().
}
}
public void doThat() {
synchronized(lock1) {
// code here is guaranteed not to be executes at the same time
// as the synchronized code in doThis().
// doMore() may execute concurrently
}
}
public void doMore() {
synchronized(lock2) {
// code here is guaranteed not to be executes at the same time
// as the synchronized code in doThis().
// doThat() may execute concurrently
}
}
}
이 질문은 스레드 세이프 싱글톤과 더블 체크 잠금에 의한 레이지 초기화와의 차이에 관한 것이라고 생각합니다.특정 싱글톤을 구현할 필요가 있을 때는 항상 이 기사를 참조합니다.
스레드 세이프 싱글톤입니다.
// Java program to create Thread Safe
// Singleton class
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
// private constructor
}
//synchronized method to control simultaneous access
synchronized public static GFG getInstance()
{
if (instance == null)
{
// if instance is null, initialize
instance = new GFG();
}
return instance;
}
}
장점:
느린 초기화가 가능합니다.
스레드 세이프입니다.
단점:
- getInstance() 메서드는 동기화되므로 여러 스레드가 동시에 액세스할 수 없기 때문에 성능이 저하됩니다.
이것은 이중 체크 잠금을 사용한 Lazy 초기화입니다.
// Java code to explain double check locking
public class GFG
{
// private instance, so that it can be
// accessed by only by getInstance() method
private static GFG instance;
private GFG()
{
// private constructor
}
public static GFG getInstance()
{
if (instance == null)
{
//synchronized block to remove overhead
synchronized (GFG.class)
{
if(instance==null)
{
// if instance is null, initialize
instance = new GFG();
}
}
}
return instance;
}
}
장점:
느린 초기화가 가능합니다.
스레드 세이프도 가능합니다.
키워드 동기화로 인한 성능 저하를 극복합니다.
단점:
첫 번째로 퍼포먼스에 영향을 줄 수 있습니다.
이중 체크 잠금 방식은 견딜 수 있으므로 고성능 멀티 스레드 애플리케이션에 사용할 수 있습니다.
상세한 것에 대하여는, 다음의 문서를 참조해 주세요.
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
스레드와 동기화합니다. 1) 작동하지 않는 스레드에서 동기화(이것)를 사용하지 마십시오.(이와 동기화하면 현재 스레드가 잠금 스레드 개체로 사용됩니다.각 스레드는 다른 스레드와는 독립적이기 때문에 동기화가 조정되지 않습니다. 2) 코드 테스트 결과 Mac의 Java 1.6에서는 메서드 동기화가 작동하지 않습니다.3) 동기(lockObj)는 동기하고 있는 모든 스레드의 공통 공유 객체입니다.4) ReenterantLock.lock() 및 .unlock()이 동작합니다.자세한 내용은 Java 튜토리얼을 참조하십시오.
다음 코드는 이러한 점을 나타냅니다.또한 ArrayList를 대체하는 스레드 세이프 벡터도 포함되어 있어 벡터에 추가하는 많은 스레드가 정보를 잃지 않고 ArrayList와 마찬가지로 정보가 손실될 수 있습니다.0) 현재 코드는 레이스 조건으로 인한 정보 손실을 나타냅니다.A) 현재 라벨이 붙은 A라인에 코멘트를 하고 그 위의 A라인에 코멘트를 해제한 후 실행하면 메서드는 데이터를 잃지만 데이터가 손실되어서는 안 됩니다.B) 스텝 A, 언코멘트 B 및 // 엔드 블록}을 역방향으로 합니다.그런 다음 를 실행하여 데이터 손실이 없는 결과를 확인합니다. C) 주석 아웃 B, 주석 해제 C.실행. 예상대로 데이터 손실 시 동기화를 참조하십시오.모든 버전을 완성할 시간이 없습니다. 도움이 되었으면 합니다.동기화가 (이것) 또는 메서드 동기화가 동작하는 경우는, 테스트한 Java 및 OS 의 버전을 기입해 주세요.감사합니다.
import java.util.*;
/** RaceCondition - Shows that when multiple threads compete for resources
thread one may grab the resource expecting to update a particular
area but is removed from the CPU before finishing. Thread one still
points to that resource. Then thread two grabs that resource and
completes the update. Then thread one gets to complete the update,
which over writes thread two's work.
DEMO: 1) Run as is - see missing counts from race condition, Run severa times, values change
2) Uncomment "synchronized(countLock){ }" - see counts work
Synchronized creates a lock on that block of code, no other threads can
execute code within a block that another thread has a lock.
3) Comment ArrayList, unComment Vector - See no loss in collection
Vectors work like ArrayList, but Vectors are "Thread Safe"
May use this code as long as attribution to the author remains intact.
/mf
*/
public class RaceCondition {
private ArrayList<Integer> raceList = new ArrayList<Integer>(); // simple add(#)
// private Vector<Integer> raceList = new Vector<Integer>(); // simple add(#)
private String countLock="lock"; // Object use for locking the raceCount
private int raceCount = 0; // simple add 1 to this counter
private int MAX = 10000; // Do this 10,000 times
private int NUM_THREADS = 100; // Create 100 threads
public static void main(String [] args) {
new RaceCondition();
}
public RaceCondition() {
ArrayList<Thread> arT = new ArrayList<Thread>();
// Create thread objects, add them to an array list
for( int i=0; i<NUM_THREADS; i++){
Thread rt = new RaceThread( ); // i );
arT.add( rt );
}
// Start all object at once.
for( Thread rt : arT ){
rt.start();
}
// Wait for all threads to finish before we can print totals created by threads
for( int i=0; i<NUM_THREADS; i++){
try { arT.get(i).join(); }
catch( InterruptedException ie ) { System.out.println("Interrupted thread "+i); }
}
// All threads finished, print the summary information.
// (Try to print this informaiton without the join loop above)
System.out.printf("\nRace condition, should have %,d. Really have %,d in array, and count of %,d.\n",
MAX*NUM_THREADS, raceList.size(), raceCount );
System.out.printf("Array lost %,d. Count lost %,d\n",
MAX*NUM_THREADS-raceList.size(), MAX*NUM_THREADS-raceCount );
} // end RaceCondition constructor
class RaceThread extends Thread {
public void run() {
for ( int i=0; i<MAX; i++){
try {
update( i );
} // These catches show when one thread steps on another's values
catch( ArrayIndexOutOfBoundsException ai ){ System.out.print("A"); }
catch( OutOfMemoryError oome ) { System.out.print("O"); }
}
}
// so we don't lose counts, need to synchronize on some object, not primitive
// Created "countLock" to show how this can work.
// Comment out the synchronized and ending {, see that we lose counts.
// public synchronized void update(int i){ // use A
public void update(int i){ // remove this when adding A
// synchronized(countLock){ // or B
// synchronized(this){ // or C
raceCount = raceCount + 1;
raceList.add( i ); // use Vector
// } // end block for B or C
} // end update
} // end RaceThread inner class
} // end RaceCondition outter class
언급URL : https://stackoverflow.com/questions/574240/is-there-an-advantage-to-use-a-synchronized-method-instead-of-a-synchronized-blo
'programing' 카테고리의 다른 글
Ubuntu 시스템에 Python이 있는데 gcc가 Python.h를 찾을 수 없습니다. (0) | 2022.07.21 |
---|---|
VueJs 2를 사용한 글로벌 데이터 (0) | 2022.07.21 |
C#의 Generics와 Java의 차이점은 무엇입니까?템플릿은 C++로 표시됩니까? (0) | 2022.07.21 |
경로와 구성 요소가 동일한 두 경로 - Vue js (0) | 2022.07.21 |
데이터 표시 가능한 여러 행 선택(Shift+Click) (0) | 2022.07.21 |