이 기사에서는 Java의 동기화 된 (객체 잠금)와 정적 동기화 (클래스 잠금)의 차이에 대해 설명합니다. 다음과 같이 참조에 대해 공유하십시오.
동기화와 정적 동기화의 차이
이 두 사용법의 분석을 분석함으로써 Java의 잠금 개념을 이해할 수 있습니다. 하나는 인스턴스 잠금입니다 (인스턴스 객체에 잠겨 있습니다. 클래스가 싱글 톤 인 경우 잠금 장치는 글로벌 잠금의 개념도 있습니다), 다른 하나는 글로벌 잠금 장치입니다 (잠금은 클래스를 대상으로합니다. 인스턴스가 얼마나 많은 객체인지, 스레드는 잠금을 공유합니다). 인스턴스 잠금은 동기화 된 키워드에 해당하는 반면 클래스 잠금 (글로벌 잠금)은 정적 동기화 된 (또는 클래스의 클래스 또는 클래스 로더 객체에 잠겨 있음)에 해당합니다.
다음 기사는 좋은 요약을 제공합니다.
1. 동기화 된 것과 정적 동기화의 차이
Synchronized는 다른 스레드가 클래스 인스턴스의 모든 동기화 된 블록에 동시에 액세스하는 것을 방지하기 위해 클래스의 현재 인스턴스 (현재 객체)를 잠금합니다. 이것은 "클래스의 현재 인스턴스"입니다. 클래스의 두 가지 다른 사례에는 그러한 제약이 없습니다.
그런 다음 정적 동기화는 클래스의 모든 인스턴스의 동시 액세스를 제어하기 위해 발생하며, 정적 동기화 된 클래스의 모든 인스턴스가 동시에 JVM의 클래스에 해당하는 코드 블록에 액세스하기 위해 클래스의 모든 인스턴스를 제한합니다. 실제로 클래스에서 메소드 또는 코드 블록에 동기화 된 경우 클래스의 인스턴스를 생성 한 후 인스턴스는 스레드가 인스턴스의 동기화 된 보호 블록에 동시에 액세스하는 것을 방지하는 모니터링 블록이 있습니다. 정적 동기화는 클래스의 모든 인스턴스에 공통적 인 모니터링 블록입니다. 이것이 두 사람의 차이입니다. 다시 말해, 동기화 된 것은 이것과 동일합니다. 동기화 된 반면, 정적 동기화 된 것은 무언가와 동일합니다. (나중에 주소)
일본 작가 인 Jie Chenghao의 "Java Multithreaded Design Pattern"은 다음과 같은 열이 있습니다.
pulbic class something () {public synchronized void issynca () {} public synchronized void void issyncb () {} public static synchronized void csynca () {} public static synchronized void csyncb () {}}따라서 클래스의 두 가지 인스턴스 x와 y가있는 경우 여러 스레드에 의해 다음 메소드 그룹에 동시에 액세스하는 경우는 무엇입니까?
axissynca () 및 x.issyncb ()
bxissynca () 및 y.issynca ()
cxcsynca () 및 y.csyncb ()
dxissynca () 및 뭔가 .csynca ()
여기에서 판단 할 수 있음이 분명합니다.
A는 모두 동일한 인스턴스 (x)에 대한 동기화 된 도메인 액세스이므로 동시에 액세스 할 수 없습니다. (멀티 스레드에서 X에 액세스하는 다른 동기화 된 도메인은 동시에 액세스 할 수 없습니다)
x.issynca ()가 여러 스레드에서 액세스되면 여전히 동일한 인스턴스이고 동일한 방법에 잠겨 있으므로 동시에 여러 스레드에서 액세스 할 수 없습니다. (멀티 스레드에서 X에 액세스하는 동일한 동기화 된 도메인은 동시에 액세스 할 수 없습니다)
B, 다른 인스턴스의 경우 동시에 액세스 할 수 있습니다 (개체 잠금에는 다른 객체 인스턴스에 대한 잠금 제약 조건이 없습니다)
C, 정적 동기화되어 있기 때문에 다른 인스턴스가 여전히 제한되며, 이는 무언가.issynca () 및 Something.issyNCB ()와 동일하므로 동시에 액세스 할 수 없습니다.
따라서 D?는 어떻습니까?이 책의 답은 동시에 액세스 할 수 있습니다. 답의 이유는 동기화 된 인스턴스 메소드와 동기화 클래스 방법이 잠금과 다르기 때문입니다.
개인 분석은 동기화되고 정적 동기화 된 두 개의 갱과 동일하며 각 갱단과 동일하며 각 갱단은 자체 제어를 가지고 있으며 서로 제약이 없으며 동시에 액세스 할 수 있습니다.
예를 들어:
public class testsynchronized {public synchronized void test1 () {int i = 5; while (i--> 0) {system.out.println (thread.currentthread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException IE) {}}} 공개 정적 동기화 된 void test2 () {int i = 5; while (i--> 0) {system.out.println (thread.currentthread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException, 즉) {}}} public static void main (String [] args) {최종 testsynchronized myt2 = new testsynchronized (); 스레드 test1 = new Thread (new Runnable () {public void run () {myt2.test1 ();}}, "test1"); 스레드 test2 = new Thread (new Runnable () {public void run () {testsynchronized.test2 ();}}, "test2"); test1.start (); test2.start (); // testRunnable tr = new testRunnable (); // 스레드 test3 = 새 스레드 (tr); // test3.start (); }}test1 : 4 test2 : 4 test1 : 3 test2 : 3 test2 : 2 test1 : 2 test2 : 1 test1 : 1 test1 : 0 test2 : 0
위의 코드는 동기화 된 정적 메소드와 인스턴스 메소드를 동시에 수정하지만 실행 결과는 번갈아 수행되며, 이는 클래스 잠금과 객체 잠금이 서로 다른 영역을 제어하는 두 개의 다른 잠금 장치이며 서로 방해하지 않음을 증명합니다. 마찬가지로, 스레드는 객체 잠금을 얻지 만, 이러한 유형의 잠금을 얻을 수 있습니다. 즉, 동시에 두 개의 잠금 장치를 얻을 수 있습니다.
결론적으로 :
A : 동기화 된 정적은 특정 클래스의 범위입니다. 동기화 된 정적 csync {}는 여러 스레드의 여러 인스턴스가 동시에 동시에 동기화 된 정적 메소드에 액세스하는 것을 방지합니다. 클래스의 모든 객체 인스턴스에서 작동합니다.
B : Synchronized는 인스턴스의 범위입니다. Synchronized Isync () {}은이 인스턴스 가이 클래스의 동기화 된 메소드에 동시에 액세스하지 못하게합니다.
실제로 요약하는 것은 매우 간단합니다.
2. 동기화 된 방법과 동기화 된 코드 빠른 차이
동기화 된 메소드 () {}와 동기화 된 (this) {} 사이에는 차이가 없지만 동기화 된 메소드 () {}는 읽기 이해력에 편리하지만 동기화 된 (this) {}는 갈등을 더 정확하게 제어 할 수 있으며 때로는 더 효율적으로 수행 할 수 있습니다.
두 가지 방법 사이의 효율 비교 :
1. 블록을 동기화하면 코드는 다음과 같습니다.
java.util.concurrent.countdownlatch import; import java.util.concurrent.executorservice; java.util.concurrent.executors import; public class testsynchronized { / ** * @param args * / public static void main (string [] args) {executorService service = executors.newCachedThreadPool (); Final CountdownLatch Cdorder = New CountdownLatch (1); Final CountdownLatch CDANSWER = New CountdownLatch (3); 최종 SynchonizedClass SC = New SynchonizedClass (); for (int i = 0; i <3; i ++) {runnable runnable = new runnable () {public void run () {try {cdorder.await (); sc.start (); cdanswer.countdown (); } catch (예외 e) {e.printstacktrace (); }}}; Service.Execute (runnable); } try {thread.sleep ((long) (math.random ()*100000); System.out.println ( "스레드" + 스레드 .currentThread (). getName () + "게시 실행 명령"); cdorder.countdown (); long begintime = System.CurrentTimeMillis (); System.out.println ( "스레드" + 스레드. cdanswer.await (); System.out.println ( "스레드" + 스레드. } catch (예외 e) {e.printstacktrace (); } service.shutdown (); }} class synchonizedclass {public void start ()는 InterruptedException {thread.sleep (100); // 다른 논리를 실행하여 시간 동기화 된 시간 (this) {system.out.println ( "10 ms로 실행했다"); }}} 작업 결과는 다음과 같습니다.
Thread Main은 실행 명령을 릴리스하고 스레드 메인이 명령을 보냈고, 결과를 기다리고 10ms를 사용했습니다.
10ms를 사용하여 실행합니다
10ms를 사용하여 실행합니다
Thread Main은 모든 응답 결과를 받았으며 취한 시간은 다음과 같습니다. 110
동기화 방법, 코드는 다음과 같습니다.
java.util.concurrent.countdownlatch import; import java.util.concurrent.executorservice; java.util.concurrent.executors import; public class testsynchronized { / ** * @param args * / public static void main (string [] args) {executorService service = executors.newCachedThreadPool (); Final CountdownLatch Cdorder = New CountdownLatch (1); Final CountdownLatch CDANSWER = New CountdownLatch (3); 최종 SynchonizedClass SC = New SynchonizedClass (); for (int i = 0; i <3; i ++) {runnable runnable = new runnable () {public void run () {try {cdorder.await (); sc.start (); cdanswer.countdown (); } catch (예외 e) {e.printstacktrace (); }}}; Service.Execute (runnable); } try {thread.sleep ((long) (math.random ()*100000); System.out.println ( "스레드" + 스레드 .currentThread (). getName () + "게시 실행 명령"); cdorder.countdown (); long begintime = System.CurrentTimeMillis (); System.out.println ( "스레드" + 스레드. cdanswer.await (); System.out.println ( "스레드" + 스레드. } catch (예외 e) {e.printstacktrace (); } service.shutdown (); }} class synchonizedclass {public synchronized void start ()는 interruptedException {thread.sleep (100); // 다른 로직 시간을 실행 // synchronized (this) {system.out.println ( "I ading 10 ms"); //}}}작업 결과는 다음과 같습니다.
Thread Main은 실행 명령을 릴리스하고 스레드 메인이 명령을 보냈고, 결과를 기다리고 10ms를 사용했습니다.
10ms를 사용하여 실행합니다
10ms를 사용하여 실행합니다
스레드 메인은 모든 응답 결과를 받았으며, 시간은 다음과 같습니다. 332
이 둘의 차이점은 222ms입니다.
비교는 동기 코드 블록이 동기화 방법보다 효율적임을 보여줍니다.
보충 기억 :
1. 동기화 된 키워드의 두 가지 범위가 있습니다.
1) 객체 인스턴스 내에 있습니다. 동기화 된 Amethod () {}는 여러 스레드 가이 객체의 동기화 된 메소드에 동시에 액세스하는 것을 방지 할 수 있습니다 (한 스레드가 동기화 된 메소드 중 하나에 액세스하는 한 객체에 여러 동기화 된 메소드가있는 경우 다른 스레드는 동시에 객체의 동기화 된 메소드에 액세스 할 수 없습니다). 현재 다른 객체 인스턴스의 동기화 된 메소드는 중단되지 않습니다. 즉, 다른 스레드는 동시에 동일한 클래스의 다른 객체 인스턴스에서 동기화 된 메소드에 여전히 액세스 할 수 있습니다.
2) 특정 클래스의 범위입니다. 동기화 된 static astaticmethod {}는 여러 스레드의 다른 인스턴스 개체 (또는 동일한 인스턴스 객체) 가이 클래스의 동기화 된 정적 메소드에 동시에 액세스하는 것을 방지합니다. 클래스의 모든 객체 인스턴스에서 작동합니다.
2. 메소드 전에 동기화 된 키워드를 사용하는 것 외에도 동기화 된 키워드를 메소드의 블록에서도 사용할 수 있으며,이 블록의 자원에 대해 상호 배타적 액세스 만 수행 함을 나타냅니다. 사용법은 다음과 같습니다. 동기화 (this) {/*block*/} (또는 동기화 (OBJ) {/*block*/}), 그 범위는 현재 객체입니다.
3. 동기화 된 키워드를 상속받을 수 없습니다. 즉, 기본 클래스 동기화 된 f () {}의 메소드는 상속 클래스에서 f () {}를 자동으로 동기화하지 않지만 f () {}가됩니다. 상속 클래스는 해당 메소드 중 하나가 동기화되어 있음을 명시 적으로 지정해야합니다.
동기화 된 (this)에 대한 약간의 이해 (객체 잠금을 잘 설명 하고이 키워드에주의를 기울이십시오).
1. 두 개의 동시 스레드가 동일한 개체 객체에서 동기화 된 (이) 동기화 된 코드 블록에 액세스하면 한 번 이내에 하나의 스레드 만 실행할 수 있습니다. 다른 스레드는 코드 블록을 실행하기 전에 현재 스레드 가이 코드 블록을 실행할 때까지 기다려야합니다.
2. 그러나 한 스레드가 객체의 동기화 된 (이) 동기화 코드 블록에 액세스하면 다른 스레드가 해당 객체의 비 동기화 된 (이) 동기화 코드 블록에 액세스 할 수 있습니다.
3. 스레드가 객체의 동기화 된 (이) 동기화 코드 블록에 액세스 할 때 다른 스레드는 객체의 다른 모든 동기화 된 (이) 동기화 코드 블록에 대한 액세스를 차단하는 것이 특히 중요합니다.
4. 세 번째 예제는 다른 동기 코드 블록에도 적용됩니다. 즉, 스레드가 객체의 동기화 된 (이) 동기화 코드 블록에 액세스하면이 객체의 객체 잠금을 얻습니다. 결과적으로, 다른 스레드는 객체 객체의 모든 동기 코드 부분에 대한 액세스가 일시적으로 차단됩니다.
5. 위 규칙은 다른 객체 잠금에도 적용됩니다.
동기화 된 키워드 테스트를 용이하게하기 위해 코드를 추가하십시오 (간단한 수정)
public class testsynchronized {public void test1 () {synchronized (this) {int i = 5; while (i--> 0) {system.out.println (thread.currentthread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException IE) {}}}} public synchronized void test2 () {int i = 5; while (i--> 0) {system.out.println (thread.currentthread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException IE) {}}} public synchronized void test3 () {int i = 5; while (i--> 0) {system.out.println (thread.currentthread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException, 즉) {}}} public static void main (String [] args) {최종 testsynchronized myt2 = new testsynchronized (); 최종 테스트 동기화 Myt3 = New TestSynchronized (); 스레드 test1 = new Thread (new Runnable () {public void run () {myt2.test2 ();}}, "test1"); 스레드 test2 = new Thread (new Runnable () {public void run () {myt2.test3 ();}}, "test3"); test1.start () ;; test2.start (); }} 실행 결과 :
test1 : 4test1 : 3test1 : 2test1 : 1test1 : 0test3 : 4test3 : 3test3 : 2test3 : 1test3 : 0
아래에서는 Java에서 Sychronized의 사용에 중점을 둡니다. Java는 구체적으로 동기화 방법과 동기화 된 블록 동기화 된 키워드입니다. 여기에는 동기화 된 메소드와 동기화 된 블록의 두 가지 사용법이 포함됩니다.
1. 동기화 된 방법 : 메소드 선언에 동기화 된 키워드를 추가하여 동기화 된 메소드를 선언합니다. 좋다:
Public Synchronized Void AccessVal (int NewVal);
동기화 된 메소드 제어 클래스 멤버 변수에 대한 액세스 : 각 클래스 인스턴스는 잠금에 해당하며 각 동기화 된 메소드는 실행되기 전에 메소드를 호출하는 클래스 인스턴스의 잠금을 얻어야합니다. 그렇지 않으면, 그것이 속한 실이 차단됩니다. 메소드가 실행되면 잠금을 독점적으로 차지합니다. 잠금은 메소드에서 돌아올 때까지 해제되지 않습니다. 차단 된 스레드는 잠금을 얻고 실행 가능 상태를 다시 입력 할 수 있습니다. 이 메커니즘은 동시에, 각 클래스 인스턴스에 대해 동시에 동기화 된 모든 멤버 기능 중 하나가 실행 가능 상태에 있음을 보장합니다 (대부분 클래스 인스턴스에 해당하는 잠금을 얻을 수 있기 때문에 클래스 멤버 변수의 액세스 충돌을 효과적으로 피할 수 있기 때문에 클래스 멤버 변수에 액세스 할 수있는 모든 방법이 선언 된 경우).
클래스 인스턴스뿐만 아니라 Java에서 각 클래스는 잠금 장치에 해당하므로 클래스의 정적 멤버 기능을 정적 동기로 선언하여 클래스의 정적 멤버 변수에 대한 액세스를 제어 할 수 있습니다.
동기화 된 방법의 단점 : 동기화 된 대규모 방법을 선언하면 효율성에 큰 영향을 미칩니다. 일반적으로 스레드 클래스의 메소드 run ()이 동기화 된 것으로 선언 된 경우, 스레드의 수명 내내 실행 되었으므로이 클래스의 동기화 된 메소드에서 성공하지 못하게됩니다. 물론 클래스 멤버 변수에 액세스하는 코드를 특수 메소드에 넣고 동기화 된 것으로 선언하고 주요 방법으로 호출 하여이 문제를 해결할 수 있지만 Java는 더 나은 솔루션, 즉 동기화 된 블록을 제공합니다.
2. 동기화 된 블록 : 동기화 된 키워드를 통해 동기화 된 블록을 선언합니다. 구문은 다음과 같습니다.
동기화 (syncobject) {// 액세스 제어를 허용하는 코드}} 동기화 된 블록은 코드가 실행되기 전에 객체 syncobject의 잠금을 얻어야하는 코드 블록입니다. 특정 메커니즘은 위에서 설명한 것과 동일합니다. 모든 코드 블록을 타겟팅 할 수 있고 잠긴 객체를 언제든지 지정할 수 있으므로 더 유연합니다.
알아채다:
동기화 된 키워드를 사용하는 경우 동기화 된 프로그램 블록이 객체 잠금을 차지하기 때문에 동기화 된 방법 또는 동기화 블록에서 수면 또는 수율 방법을 사용하지 않아야하므로 휴식을 취하면 다른 스레드는 깨어나서 실행되기를 기다리는 동안에 만 실행할 수 있습니다. 효율성에 심각한 영향을 미칠뿐만 아니라 논리적이지 않습니다.
마찬가지로, 잠금 장치를 점유하고 다른 MUTEX 스레드는 여전히 동기 프로그램 블록에 액세스 할 수 없기 때문에 CPU 자원을 포기하기 위해 동기 프로그램 블록의 Yeild 메소드를 호출하는 것은 합리적이지 않습니다. 물론 동기 프로그램 블록과 관련이없는 스레드는 더 많은 실행 시간을 얻을 수 있습니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.