Java 5 이전에 동기화 된 키워드를 사용하여 잠금 기능을 구현했습니다.
동기화 된 키워드는 수정 자 (동기화 된 메소드) 또는 함수 내의 문 (동기화 된 코드 블록)으로 사용할 수 있습니다.
동기화 된 마스터를 마스터하려면 열쇠는 그 물건을 잠금으로 사용하는 것입니다. 클래스의 비 정적 메소드 (멤버 메소드)의 경우 객체 인스턴스의 잠금을 얻는 것을 의미합니다. 클래스의 정적 방법 (클래스 메소드)의 경우 클래스 객체의 잠금을 얻어야합니다. 동기 코드 블록의 경우 획득 할 객체의 잠금 장치를 지정해야합니다. 동기화되지 않은 비 정적 메소드는 전체 메소드를 포함하는 동기화 된 (this) {…} 코드 블록으로 간주 될 수 있습니다.
동기 코드 블록이든 동기화 메소드이든, 한 번에 한 번만 입력 할 수 있습니다 (최대 한 스레드는 동시에 코드 세그먼트를 실행합니다.) 다른 스레드가 입력하려고하면 (동일한 동기 블록이든 다른 동기화 블록이든) JVM은이를 중단합니다 (대기 잠금 풀에 넣음). 이 구조는 동시성 이론에서 중요한 섹션이라고합니다.
JVM에서 효율성을 향상시키기 위해 동시에 실행되는 각 스레드에는 처리중인 데이터의 캐시 사본이 있습니다. 동기화를 위해 동기화 된 것을 사용하면 실제로 동기화 된 것은 다른 스레드에서 잠긴 객체를 나타내는 메모리 블록입니다 (복사 데이터는 기본 메모리와 동기화됩니다. 이제 우리는 왜 단어 동기화가 사용되는지 알 수 있습니다). 간단히 말해서, 동기화 블록 또는 동기화 메소드가 실행 된 후에 잠금 객체에 대한 수정은 잠금을 풀기 전에 주 메모리에 다시 작성해야합니다. 동기화 블록을 입력하고 잠금을 얻은 후, 잠긴 객체의 데이터는 주 메모리에서 읽히고 잠금을 고정하는 스레드의 데이터 사본은 기본 메모리의 데이터보기와 동기화되어야합니다.
다음은 동기화 된 다양한 상황을 설명하기위한 구체적인 예입니다.
동기화 된 동기화 방법
먼저 동기화 방법의 예를 살펴 보겠습니다.
public class synchronizedTest1은 스레드를 확장합니다. {private synchronized void testsynchronizedMethod () {for (int i = 0; i <10; i ++) {system.out.println (thread.currentThread (). getName () + "testsynchronizedmedod :" + i); try {thread.sleep (100); } catch (InterruptedException e) {e.printstacktrace (); }}} @override public void run () {testsynchronizedmethod (); } public static void main (String [] args) {synchronizedTest1 t = new SynchronizedTest1 (); t.start (); t.testsynchronizedmethod (); }}프로그램 출력 실행 :
메인 테스트 동기화 된 제조 : 0 주요 테스트 동기화 메드드 : 1 주요 TestSynchronizedMethod : 2 주요 TestSynchronizedMethod : 3 주요 테스트 동기화 된 제조 : 4 주요 테스트 동기화 된 제조 : 5 주요 테스트 동기화 메드 : 6 주요 테스트 동시대화 메드 : 7 메인 테스트 동기화 메인 메인 메인 삭제. TestSynchronizedMethod : 9 Thread-0 TestsynchronizedMethod : 0 Thread-0 TestSynchronizedMethod : 1 Thread-0 TestsynchronizedMethod : 2 Thread-0 TestSynchronizedMethod : 3 Thread-0 TestSynchronizedMethod : 4 Thread-0 TestsynchronizedMethod : 5 스레드 -0 Testsyn-konizedmethod : 4 Thread-0 Testsynizeed-Chonized-Chonizeed-Chonizeed-Chonized. TestSynCronizedMethod : 7 Thread-0 TestSynchronizedMethod : 8 Thread-0 TestSynchronizedMethod : 9
TestSynchronizedMethod 메소드가 두 스레드 사이에서 동기식으로 실행된다는 것을 알 수 있습니다.
기본 메소드가 다음으로 수정되면 두 스레드의 동기화 모니터는 동일한 객체가 아니며 동기 역할을 수행 할 수 없기 때문에 두 스레드는 동기식으로 실행할 수 없습니다.
public static void main (String [] args) {스레드 t = new SynchronizedTest1 (); t.start (); 스레드 t1 = 새로운 synchronizedTest1 (); t1.start (); }출력 결과는 다음과 같습니다.
Thread-0 TestSynchronizedMethod : 0 Thread-1 TestsynchronizedMetrod : 0 Thread-0 TestSynchronizedMethod : 1 Thread-1 TestsynchronizedMethod : 1 Thread-0 TestSynchronizedMethod : 2 Thread-1 TestsynchronizedMethod : 2 Thread-0 TestsynchronizedMethod : 3 Thread-1 Testsynized-1-3 Testsynized Methronized. TestSynchronizedMethod : 4 Thread-1 TestsynchronizedMethod : 4 Thread-0 TestSynchronizedMethod : 5 Thread-1 TestsynchronizedMethod : 5 Thread-0 TestsynchronizedMethod : 6 Thread-1 TestSynchronizedMethod : 6 Thread-0 TestsynchronizedMethod : 7 Thread-1 Testsymodod : 7 Thread-1 Testythod : 7 Thread-1 chontod. TestSynCronizedMethod : 8 Thread-1 TestsynchronizedMethod : 8 Thread-0 TestSynchronizedMethod : 9 Thread-1 TestSynchronizedMethod : 9
수정 된 기본 메소드를 두 스레드 사이에서 동기로 실행할 수있는 경우, TestSynchronizedMethod 메소드는 정적 메소드로 선언되어야하므로 두 스레드의 모니터가 동일한 개체 (클래스 객체)이므로 동기식으로 실행할 수 있습니다. 수정 된 코드는 다음과 같습니다.
public class synchronizedTest1은 스레드를 확장합니다. {private static synchronized void testsynchronizedMethod () {for (int i = 0; i <10; i ++) {system.out.println (thread.currentThread (). getName () + "testSynchronizedMethod :" + i); try {thread.sleep (100); } catch (InterruptedException e) {e.printstacktrace (); }}} @override public void run () {testsynchronizedmethod (); } public static void main (String [] args) {스레드 t = new SynchronizedTest1 (); t.start (); 스레드 t1 = 새로운 synchronizedTest1 (); t1.start (); }}출력 결과는 다음과 같습니다.
Thread-0 TestSynchronizedMethod : 0 Thread-0 TestSynchronizedMethod : 1 Thread-0 TestSynchronizedMethod : 2 Thread-0 TestsynchronizedMethod : 3 Thread-0 TestSynchronizedMethod : 4 Thread-0 TestsynchronizedMethod : 5 Thread-0 TestsynchronizedMethod : 6 Thread-0 TestsynchonizedMethod : 7 Thread-0 Testsynchonize TestSynchronizedMethod : 8 Thread-0 TestsynchronizedMethod : 9 Thread-1 TestSynchronizedMethod : 0 Thread-1 TestSynchronizedMethod : 1 Thread-1 TestSynchronizedMethod : 2 Thread-1 TestsynchronizedMethod : 3 Thread-1 TestsynchronizedMethod : 4 Thread-1 TestSynized-1-6 TestSynized-1- testsynchronizedmethod : 7 Thread-1 TestsynchronizedMethod : 8 Thread-1 TestsynchronizedMethod : 9
동기 블록의 상황은 동기화 블록이 동기화 제어의 세분성을 감소시켜 다중 스레드 병렬 실행의 효율을 더 잘 발휘할 수 있다는 점을 제외하고는 동기화 방법과 유사합니다.
이 개체를 사용하여 동일한 개체 인스턴스 간의 동기화를 제어합니다.
public class synchronizedtest2 스레드 {private void testsynchronizedBlock () {synchronized (this) {for (int i = 0; i <10; i ++) {system.out.println (thread.currentthread (). getName () + "testSynchronizedBlock :" + i); try {thread.sleep (100); } catch (InterruptedException e) {e.printstacktrace (); }}}} @override public void run () {testsynchronizedBlock (); } public static void main (String [] args) {synchronizedTest2 t = new SynchronizedTest2 (); t.start (); t.testsynchronizedBlock (); }}출력 결과 :
메인 테스트 동기화 된 블록 : 0 메인 테스트 동기화 된 블록 : 1 메인 테스트 동기화 된 블록 : 2 메인 테스트 동기화 된 블록 : 3 메인 테스트 동기화 된 블록 : 4 주요 테스트 동기화 된 블록 : 5 메인 테스트 동기화 된 블록 : 6 메인 테스트 동기화 된 블록 : 7 메인 테스트 동시대화 블록 : 8 메인 테스트 동시대화 : 9 메인 테스트 동시에. TestSynchronizedBlock : 0 Thread-0 TestsynchronizedBlock : 1 Thread-0 TestSynchronizedBlock : 2 Thread-0 TestSynchronizedBlock : 3 Thread-0 TestSynchronizedBlock : 4 Thread-0 TestSynchronizedBlock : 5 Thread-0 TestsynchronizedBlock : 5 Thread-0 TestsynchronizedBlock : 7 스레드-0 TestsyRonized- 8 THREARD-0 TESTSYNCRONIZED testsynchronizedblock : 9
클래스 객체를 사용하여 다른 인스턴스 간의 동기화를 제어합니다.
public class synchronizedTest2 스레드 {private void testsynchronizedBlock () {synchronized (synchronizedTest2.class) {for (int i = 0; i <10; i ++) {system.out.println (thread.currentthread (). getName () + " + i); try {thread.sleep (100); } catch (InterruptedException e) {e.printstacktrace (); }}}} @override public void run () {testsynchronizedBlock (); } public static void main (String [] args) {스레드 t = new SynchronizedTest2 (); t.start (); 스레드 t2 = 새로운 synchronizedTest2 (); t2.start (); }}출력 결과 :
Thread-0 TestSynchronizedBlock : 0 Thread-0 TestSynchronizedBlock : 1 Thread-0 TestSynchronizedBlock : 2 Thread-0 TestsynchronizedBlock : 3 Thread-0 TestsynchronizedBlock : 4 스레드 -0 TestSynchronizedBlock : 5 Thread-0 TestSynchronizedBlock : 6 Thread-0 TestsynizedBlock : 7 Thread-0 TestsynizedBlock Thread-0 TestSynchronizedBlock : 9 Thread-1 TestsynchronizedBlock : 0 Thread-1 TestsynchronizedBlock : 1 Thread-1 TestsynchronizedBlock : 2 Thread-1 TestsynchronizedBlock : 3 Thread-1 TestsynchronizedBlock : 4 Thread-1 TestsynchronizedBlock : 5 Thread-1 TestsynchronizedBlock : 6 Thread-1 Testsynizeed Block : 7 Thread-1 Testsynized Block : 7 Thread-1 TestSynchronizedBlock : 8 Thread-1 TestSynchronizedBlock : 9
동기화 제어를 위해 동기화 된 키워드를 사용하는 경우 객체 모니터를 잡아야합니다. 모니터를 얻는 프로세스 만 실행할 수 있으며 모니터를 얻기 위해 다른 모든 것을 기다려야합니다. 널이 아닌 객체는 객체 모니터로 사용할 수 있습니다. 메소드에서 동기화 된 Acts가 있으면 객체 인스턴스가 잠겨 있습니다. 정적 메소드에서 작용할 때 객체 인스턴스가 객체에 해당하는 잠겨 있습니다.
두 스레드가 객체에 동시에 액세스하는 동기 메소드
두 개의 동시 스레드가 동일한 객체의 동기 메소드에 액세스하면 하나의 스레드 만 실행할 수 있습니다. 다른 스레드는 현재 스레드가 실행되기 전에이를 실행할 때까지 기다려야합니다.
public class twothread {public static void main (String [] args) {Final Twothread twothread = new twothread (); 스레드 t1 = new Thread (new Runnable () {public void run () {twothread.syncmethod ();}}, "a"); 스레드 t2 = new Thread (new Runnable () {public void Run () {twothread.syncMethod ();}}, "b"); t1.start (); t2.start (); } public synchronized void syncmethod () {for (int i = 0; i <5; i ++) {system.out.println (thread.currentthread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException IE) {}}}}출력 결과 :
A : 0A : 1A : 2A : 3A : 4B : 0B : 1B : 2B : 3B : 4
두 객체의 동기화 방법은 두 스레드로 액세스됩니다.
이 경우 일반적인 방법과 마찬가지로 동기화 된 것은 작동하지 않습니다. 해당 잠금 장치는 해당 객체이기 때문입니다.
public class twoObject {public static void main (String [] args) {Final TwoObject Object1 = new TwoObject (); 스레드 t1 = new Thread (new Runnable () {public void run () {object1.syncmethod ();}}, "object1"); t1.start (); Final TwoObject Object2 = New TwoObject (); 스레드 t2 = new Thread (new Runnable () {public void run () {public void run () {object2.syncmethod ();}}, "object2"); t2.start (); } public synchronized void syncmethod () {for (int i = 0; i <5; i ++) {system.out.println (thread.currentthread (). getName () + ":" + i); try {thread.sleep (500); } catch (InterruptedException IE) {}}}}가능한 출력 중 하나 :
Object2 : 0object1 : 0object1 : 1object2 : 1object2 : 2object1 : 2object2 : 3object1 : 3object1 : 4object2 : 4
두 스레드는 동기화 된 정적 메소드에 액세스합니다
이 경우 클래스가 잠겨 있으므로 언제든지 하나의 스레드 만 정적 메소드를 실행할 수 있습니다.
동기식 메소드 및 비동기 메소드에 동시에 액세스 한 스레드가 객체의 하나의 동기화 메소드에 액세스 할 때 다른 스레드는 여전히 해당 객체의 비동기 메소드에 액세스 할 수 있습니다.
public class syncandnosync {public static void main (String [] args) {Final SyncandNosync SyncandNosync = new SyncandNosync (); 스레드 t1 = new Thread (new Runnable () {public void run () {syncandnosync.syncmethod ();}}, "a"); t1.start (); 스레드 t2 = new Thread (new Runnable () {public void run () {syncandnosync.nosyncmethod ();}}, "b"); t2.start (); } public synchronized void syncmethod () {for (int i = 0; i <5; i ++) {system.out.println (struch.currentthread (). getName () + "at syncMethod () :" + i); try {thread.sleep (500); } catch (InterpruptedException, 즉) {}}} public void nosyncMethod () {for (int i = 0; i <5; i ++) {system.out.println (thread.currentThread (). getName () + "at nosyncMethod () :" + i); try {thread.sleep (500); } catch (InterruptedException IE) {}}}}하나의 가능한 출력 :
b at nosyncmethod () : 0a at syncmethod () : 0b at nosyncmethod () : 1a at syncmethod () : 1b at nosyncmethod () : 2a at syncmethod () : nosyncmethod () : nosyncmethod () : 3a at syncmethod () : 3a at syncmedod () : 4b at at. nosyncMethod () : 4
동일한 객체에 액세스하기위한 다른 동기화 방법
스레드가 객체의 동기화 메소드에 액세스하면 다른 스레드는 객체의 다른 모든 동기화 방법에 액세스 할 수 있습니다. 첫 번째 스레드는 객체 잠금을 얻었고 다른 스레드는 잠금을 얻을 수 없지만 다른 방법에 액세스하고 있지만 잠금을 얻지 못하고 액세스 할 수 없습니다.
public class twosyncmethod {public static void main (String [] args) {Final TwosyncMethod twosyncmethod = new TwosyncMethod (); 스레드 t1 = new Thread (new Runnable () {public void run () {twosyncMethod.syncMethod1 ();}}, "a"); t1.start (); 스레드 t2 = new Thread (new Runnable () {public void run () {twosyncMethod.syncMethod2 ();}}, "b"); t2.start (); } public synchronized void syncmethod1 () {for (int i = 0; i <5; i ++) {system.out.println (struch.currentthread (). getName () + "at syncMethod1 () :" + i); try {thread.sleep (500); } catch (InterruptedException, 즉) {}}} public synchronized void syncmethod2 () {for (int i = 0; i <5; i ++) {system.out.println (strook.currentThread (). getName () + "at syncMethod2 () :" + i); try {thread.sleep (500); } catch (InterruptedException IE) {}}}}출력 결과 :
a at syncmethod1 () : 0a at syncmethod1 () : 1a at syncmethod1 () : 2a at syncmethod1 () : 3a at syncmethod1 () : 4b at syncmethod2 () : 0b syncmethod2 () : 1b syncmethod2 () : 2b at syncmethod2 () : syncmethod2 () : 4