문제

할 수 있는 하나 말의 활용에 동기화 방법을 통해 동기화된 블록으로 예?

도움이 되었습니까?

해결책

할 수 있는 사람을 말의 활용에 동기화 방법을 통해 동기화된 블록으로 예?감사합니다.

거기에 명확하지 않을 사용하는 장점이 동기화 방법을 통해 블록입니다.

아마 하나(그러나 나는 그것에게 이점)은 당신이 필요하지 않 객체 참조 this.

방법:

public synchronized void method() { // blocks "this" from here.... 
    ...
    ...
    ...
} // to here

블:

public void method() { 
    synchronized( this ) { // blocks "this" from here .... 
        ....
        ....
        ....
    }  // to here...
}

십니까?아 장점이다.

블록 보다 뛰어난 장점이 있지 방법이지만,대부분의 유연성에 사용할 수 있기 때문에 또 다른 개체로 잠그는 반면 동기화 방법은 잠금의 전체 개체입니다.

Compare:

// 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
}

따라서 소비자는 여전히 읽을 수 있으며 생산자는 잠겨 있습니다.

동기화 된 방법

동기화 된 방법에는 두 가지 효과가 있습니다.
먼저, 한 스레드가 객체에 대해 동기화 된 메소드를 실행하는 경우, 첫 번째 스레드가 객체와 함께 수행 될 때까지 동일한 개체 블록에 동기화 된 메소드 (SUSTNEND EXECUTION)에 대해 동기화 된 메소드를 호출하는 다른 모든 스레드를 실행할 때.

둘째, 동기화 된 메소드가 종료되면 동일한 오브젝트에 대한 동기화 된 메소드의 후속 호출과의 관계와의 관계를 자동으로 설정합니다. 이를 통해 객체의 상태 변경이 모든 스레드에 표시됩니다.

생성자는 동기화 할 수 없습니다. 생성자와 동기화 된 키워드를 사용하는 것은 구문 오류입니다. 객체를 생성하는 스레드 만 구성하는 동안 객체에 액세스해야하기 때문에 생성자 동기화는 의미가 없습니다.

동기화 된 문

동기화 된 방법과 달리 동기화 된 문은 고유 잠금을 제공하는 객체를 지정해야합니다. 대부분 종종 목록이나 맵에 대한 액세스를 동기화하는 데 사용하지만 객체의 모든 방법에 대한 액세스를 차단하고 싶지는 않습니다.

Q : 고유 잠금 및 동기화 동기화는 고유 잠금 또는 모니터 잠금으로 알려진 내부 엔터티 주위에 구축됩니다. (API 사양은 종종이 엔티티를 단순히 단순히 "모니터"라고합니다.) 고유의 잠금은 동기화의 두 측면에서 역할을합니다. 즉, 객체의 상태에 대한 독점 액세스를 시행하고 가시성에 필수적인 관계를 확립합니다.

모든 물체에는 그것과 관련된 고유 잠금 장치가 있습니다. 컨벤션에 의해, 객체의 필드에 대한 독점적이고 일관된 액세스가 필요한 스레드는 객체의 고유 잠금 잠금 장치를 액세스하기 전에 획득 한 다음, 본질적인 잠금 장치가 완료 될 때 내장 잠금 장치를 해제해야합니다. 스레드는 잠금을 얻은 시간 사이에 고유 잠금 장치를 소유하고 있다고합니다. 스레드가 고유 잠금 장치를 소유하는 한 다른 스레드는 동일한 잠금을 얻을 수 없습니다. 다른 스레드는 잠금을 얻으려고 할 때 차단됩니다.

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();
    }
}

교차 점검 동기화 된 방법, 블록 및 동기화없이 다른 출력.

메모: 공전 동기화 된 메소드 및 블록은 클래스 객체에서 작동합니다.

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_SynChronized 플래그 세트가 있음을 식별 한 다음 객체의 잠금을 자동으로 획득하고 메소드를 호출하고 잠금을 해제합니다. 예외가 발생하면 스레드가 자동으로 잠금을 출시합니다.

반면에 메소드 블록 동기화는 객체의 잠금 및 예외 처리에 대한 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() 방법 우리는 싱글 톤 인스턴스를 만드는 데 사용되는 코드의 임계 섹션 만 잠급니다. 잠금은 한두 번만 필요하기 때문에 성능을 크게 향상시킵니다.

동기화 된 메소드를 사용하는 동안 정적 동기화 된 동기화 및 비 정적 동기화 된 메소드를 모두 혼합하면 추가주의를 기울여야합니다.

가장 자주 나는 이것을 사용하여 목록이나지도에 대한 액세스를 동기화하지만 객체의 모든 방법에 대한 액세스를 차단하고 싶지는 않습니다.

다음 코드에서 하나의 스레드를 수정하는 스레드는 맵을 수정하는 스레드를 기다리는 차단되지 않습니다. 메소드가 객체에 동기화 된 경우, 수정중인 수정이 충돌하지 않더라도 각 방법은 기다려야합니다.

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;
}

동기화 된 블록을 사용하면 여러 개의 동기화제를 가질 수 있으므로 동시에 동시이지만 비 분쇄가 동시에 진행될 수 있습니다.

반사 API를 사용하여 동기화 된 방법을 확인할 수 있습니다. 이것은 다음과 같은 일부 계약을 테스트하는 데 유용 할 수 있습니다. 모델의 모든 메소드는 동기화됩니다.

다음 스 니펫은 해시 가능의 모든 동기화 된 방법을 인쇄합니다.

for (Method m : Hashtable.class.getMethods()) {
        if (Modifier.isSynchronized(m.getModifiers())) {
            System.out.println(m);
        }
}

동기화 된 블록 사용에 대한 중요한 참고 사항 : 잠금 객체로 사용하는 것을 조심하십시오!

위의 user2277816의 코드 스 니펫은 문자열 리터럴에 대한 참조가 잠금 객체로 사용된다는 점 에서이 점을 보여줍니다. 문자열 리터럴이 자바에서 자동으로 인턴되어 문제를보기 시작해야합니다. 문자 그대로 "잠금"에 동기화되는 모든 코드 조각은 동일한 잠금을 공유합니다! 이로 인해 완전히 관련이없는 코드가있는 교착 상태로 이어질 수 있습니다.

조심 해야하는 것은 단지 문자열 객체가 아닙니다. 상자에 걸린 프리미티브는 또한자가 옥싱과 가치의 가치가 값에 따라 동일한 객체를 재사용 할 수 있기 때문에 위험합니다.

자세한 내용은 다음을 참조하십시오.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 그렇지 않으며 동기화 된 키워드를 설정하거나 컬렉션을 호출해야합니다. 동기화 된 방법 :

Map myMap = Collections.synchronizedMap (myMap); // single lock for the entire map
List myList = Collections.synchronizedList (myList); // single lock for the entire list

유일한 차이점은: 동기화된 블록을 세분화 할 수 있습 잠금과는 달리 동기화 방법

기본적으로 synchronized 블록이나 방법을 쓰는 데 사용되는 스레드에 안전한 코드를 방지하여 메모리에 불일치 오류가 있습니다.

이 질문은 매우 오래되고 많은 것이 변경되었는 동안 지난 7 년입니다.새로운 프로그래밍을 도입되었을 위한 스레드에 안전합니다.

을 달성할 수 있는 스레드에 안전을 사용하여 고급 concurrency API 신 synchronied 블록이 있습니다.이 문서 페이지 제공하는 프로그래밍을 달성하는 스레드에 안전합니다.

잠체 잠금을 지원 숙어는 단순화하는 동시에 많은 응용 프로그램.

집행 을 정의 높은 수준의 위한 API 를 실행 및 관리 실이다.실행자 구현에 의해 제공됩 java.util.동시에 제공한 스레드 풀을 관리한 대규모 응용 프로그램.

동시 컬렉션 보다 쉽게 관리할 수 있습니의 큰 컬렉션 데이터를 크게 줄일 수 있습에 대한 필요합니다.

원자 변수 는 기능을 최소화하는 동기화 및 방지하는 데 도움이 일관성 메모리 오류가 있습니다.

ThreadLocalRandom (에 JDK7)가 제공하는 효율적인 의사 난수의 생성 번호에서 여러 스레드입니다.

더 나은 교환을 위한 동기화 스에 초점을 맞추고, 을 사용하는 Lock API

는 재진입 상호 배제 자물쇠와 같은 기본적인 행동과 의미를 암시적으로 모니터 잠금을 사용하여 액세스 동기화 방법과 문장이지만,확장된 기능이다.

예를 잠금:

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.동java.util.동시에 이루어 집니다.atomic 패키지 너무 다른 프로그램을 구성 합니다.

이와 관련된 질문이 너무:

동기화 vs 잠금

동기화 된 메소드는 모든 객체 동기화 된 블록을 잠그기 위해 사용됩니다.

일반적으로 이들은 사용중인 객체의 모니터에 대해 명시 적 으로이 객체와 암시적인 것 외에는 대부분 동일합니다. 때때로 간과되는 동기화 된 메소드의 단점 중 하나는 "이"참조를 사용하여 동기화에 대한 언급이 동일한 객체에서 외부 객체가 잠글 수있는 가능성을 열어두고 있다는 것입니다. 당신이 그것을 달리면 그것은 매우 미묘한 버그 일 수 있습니다. 내부 명시 적 개체 또는 기타 기존 필드에서 동기화하면이 문제를 피할 수 있으며 동기화를 완전히 캡슐화 할 수 있습니다.

이미 언급했듯이 동기화 된 블록은 동기화 된 기능이 "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 동시성에서 (pg. 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

동기화 된 문 (§14.17)은 객체에 대한 참조를 계산합니다. 그런 다음 해당 객체에 대한 잠금 작업을 수행하려고 시도하고 잠금 작업이 성공적으로 완료 될 때까지 더 이상 진행되지 않습니다. ...

동기화 된 방법 (§8.4.3.5)은 호출 될 때 잠금 조치를 자동으로 수행합니다. 잠금 작업이 성공적으로 완료 될 때까지 본체가 실행되지 않습니다. 메소드가 인스턴스 메소드 인 경우, 그것은 호출 된 인스턴스와 관련된 잠금을 잠금합니다 (즉, 방법의 본체 실행 중에 이것으로 알려진 객체). 메소드가 정적 인 경우, 메소드가 정의 된 클래스를 나타내는 클래스 객체와 관련된 잠금 장치를 잠금합니다. ...

이 설명을 바탕으로, 대부분의 이전 답변은 정확하다고 말하고 동기화 된 메소드는 정적 메소드에 특히 유용 할 수 있으며, 그렇지 않으면 메소드가있는 클래스를 나타내는 클래스 객체를 얻는 방법을 알아 내야합니다. 한정된."

편집 : 나는 원래 이것이 실제 Java 사양의 인용문이라고 생각했습니다. 이 페이지는 단지 사양의 요약/설명 일 뿐이라는 것을 명확히했습니다.

TLDR; 도를 사용하여 synchronized 수정이나 synchronized(this){...} 식만 synchronized(myLock){...}myLock 최종 인스턴스 분야를 들고 프라이빗 개체입니다.


의 차이를 사용하는 synchronized 수정 방법을 선언하고 synchronized(..){ } 식 방법에 있어서 몸체는 이것:

  • synchronized 수정자를 지정하는 방법에의 서명
    1. 에서 볼 수 있 생성 JavaDoc,
    2. 프로그래밍 방식으로를 통해 확정 반사 테스트할 때 방법의 수정을 위한 수정자.동,
    3. 적은 입력이 필요합과 움푹 들어감에 비해 synchronized(this) { .... }, 고
    4. (에 따라 IDE)에 표시되는 클래스의 개요 및 코드가 완료되면,
    5. this 체로 잠금을 때 선언에 정적이 아닌 방법이나 바깥쪽 클래스 선언된 경우에는 정적 방법입니다.
  • synchronized(...){...} 식할
    1. 만 동기화 실행의 부분의 방법의 몸,
    2. 에서 사용할 수 있 생성자 또는 은(static)초기화 블록,
    3. 선택하면 잠금 객체를 제어하는 동기화된 액세스입니다.

그러나 사용 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
        }
    }
}

나는이 질문이 그 사이의 차이에 관한 것이라고 생각합니다 스레드 안전 싱글 톤 그리고 이중 점검 잠금으로 게으른 초기화. 특정 싱글 톤을 구현해야 할 때는 항상이 기사를 참조합니다.

글쎄, 이것은 a입니다 스레드 안전 싱글 톤:

// 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; 
  } 
} 

장점 :

  1. 게으른 초기화가 가능합니다.

  2. 스레드 안전합니다.

단점 :

  1. getInstance () 메소드는 동기화되므로 여러 스레드가 동시에 액세스 할 수 없으므로 성능이 느려집니다.

이것은 이중 점검 잠금으로 게으른 초기화:

// 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; 
  } 
} 

장점 :

  1. 게으른 초기화가 가능합니다.

  2. 또한 스레드 안전합니다.

  3. 동기화 된 키워드로 인해 성능 감소가 극복됩니다.

단점 :

  1. 처음으로 성능에 영향을 줄 수 있습니다.

  2. 단점으로. 이중 점검 잠금 방법의 경우가 적합하므로 고성능 다중 스레드 애플리케이션에 사용할 수 있습니다.

자세한 내용은이 기사를 참조하십시오.

https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/

스레드와 동기화. 1) 스레드에서 동기화 된 (이)를 사용하지 마십시오. 작동하지 않습니다. (this)와 동기화는 현재 스레드를 잠금 스레드 개체로 사용합니다. 각 스레드는 다른 스레드와 무관하므로 동기화의 조정이 없습니다. 2) 코드 테스트는 Mac의 Java 1.6에서 메소드 동기화가 작동하지 않음을 보여줍니다. 3) Lockobj가 동기화하는 모든 스레드의 공통 공유 객체 인 경우 동기화 (Lockobj)는 작동합니다. 4) ReenterantLock.lock () 및 .unlock () 작업. 이를 위해 Java 튜토리얼을 참조하십시오.

다음 코드는 이러한 점을 보여줍니다. 또한 Arraylist로 대체되는 스레드 안전 벡터가 포함되어 있으며 벡터에 추가하는 많은 스레드가 정보를 잃지 않으며 Arraylist와 동일하게 정보를 잃을 수 있습니다. 0) 현재 코드는 레이스 조건으로 인한 정보 손실을 보여줍니다. a) 현재 라벨이 표시된 선을 주석하고 그 위의 라인을 무례한 다음 실행하고 메소드는 데이터를 잃어 버리지 않아야합니다. b) 리버스 단계 A, 타협 B 및 // 엔드 블록}. 그런 다음 결과를 확인하기 위해 실행 데이터 손실 C) 댓글 B, 무관심 C. 실행, 예상대로 데이터가 손실되는 동기화를 참조하십시오. 모든 변형을 완료 할 시간이 없으며 이것이 도움이되기를 바랍니다. 동기화 (this) 또는 메소드 동기화가 작동하는 경우 테스트 한 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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top