java synchronized what is thread synchronization java
이 튜토리얼은 Java Lock, Race Condition, Mutex, Java Volatile & Deadlock과 같은 관련 개념과 함께 Java의 스레드 동기화에 대해 설명합니다.
여러 스레드가 관련된 멀티 스레딩 환경에서 둘 이상의 스레드가 동시에 동일한 리소스를 가져 오려고하면 충돌이 발생합니다. 이러한 간섭으로 인해 '경주 조건'이 발생하므로 프로그램이 예기치 않은 결과를 생성합니다.
예를 들면 단일 파일이 두 개의 스레드에 의해 업데이트되고 있습니다. 한 스레드 T1이이 파일을 업데이트하는 중이면 변수를 말합니다. 이제 T1에 의한이 업데이트가 아직 진행중인 동안 두 번째 스레드 T2도 동일한 변수를 업데이트한다고 가정 해 보겠습니다. 이렇게하면 변수가 잘못된 결과를 제공합니다.
=> 여기에서 전체 Java 교육 시리즈를 확인하십시오.
여러 스레드가 관련되면 한 번에 단일 스레드에서 리소스에 액세스 할 수있는 방식으로 이러한 스레드를 관리해야합니다. 위의 예에서 두 스레드가 액세스하는 파일은 T1이 파일에 액세스 할 때까지 T2가 파일에 액세스 할 수 없도록 관리해야합니다.
이것은 Java에서 ' 스레드 동기화 ”.
학습 내용 :
자바의 스레드 동기화
Java는 다중 스레드 언어이므로 스레드 동기화는 응용 프로그램에서 여러 스레드가 병렬로 실행되므로 Java에서 매우 중요합니다.
우리는 키워드를 사용합니다 '동기화' 과 '휘발성 물질' Java에서 동기화를 달성하려면
공유 객체 또는 리소스가 변경 가능할 때 동기화가 필요합니다. 자원이 변경 불가능한 경우 스레드는 동시에 또는 개별적으로 만 자원을 읽습니다.
이 경우 리소스를 동기화 할 필요가 없습니다. 이 경우 JVM은 Java 동기화 코드는 한 번에 하나의 스레드에서 실행됩니다. .
대부분의 경우 Java의 공유 리소스에 대한 동시 액세스로 인해 '메모리 불일치'및 '스레드 간섭'과 같은 오류가 발생할 수 있습니다. 이러한 오류를 방지하려면 이러한 리소스에 대한 액세스가 상호 배타적 일 수 있도록 공유 리소스를 동기화해야합니다.
우리는 동기화를 구현하기 위해 모니터링합니다. 모니터는 한 번에 하나의 스레드에서만 액세스 할 수 있습니다. 스레드가 잠금을 획득하면 스레드가 모니터에 들어갔다고 말할 수 있습니다.
특정 스레드가 모니터에 액세스 할 때 모니터는 잠기고 모니터에 들어 가려는 다른 모든 스레드는 액세스하는 스레드가 완료되고 잠금을 해제 할 때까지 일시 중단됩니다.
앞으로이 자습서에서는 Java에서의 동기화에 대해 자세히 설명합니다. 이제 Java에서의 동기화와 관련된 몇 가지 기본 개념에 대해 설명하겠습니다.
자바의 경쟁 조건
다중 스레드 환경에서 둘 이상의 스레드가 동시에 쓰기 위해 공유 리소스에 액세스하려고하면 여러 스레드가 서로 경쟁하여 리소스 액세스를 완료합니다. 이로 인해 '경주 상태'가 발생합니다.
고려해야 할 한 가지는 여러 스레드가 읽기 전용으로 공유 리소스에 액세스하려고 시도하는 경우 문제가 없다는 것입니다. 여러 스레드가 동시에 동일한 리소스에 액세스 할 때 문제가 발생합니다.
경쟁 조건은 프로그램에서 스레드의 적절한 동기화 부족으로 인해 발생합니다. 한 번에 하나의 스레드 만 리소스에 액세스하고 경쟁 조건이 존재하지 않도록 스레드를 적절히 동기화 할 때.
그렇다면 경쟁 조건을 어떻게 감지합니까?
경합 상태를 감지하는 가장 좋은 방법은 코드 검토입니다. 프로그래머로서 우리는 발생할 수있는 잠재적 인 경쟁 조건을 확인하기 위해 코드를 철저히 검토해야합니다.
자바의 잠금 / 모니터
동기화를 구현하기 위해 모니터 또는 잠금을 사용한다고 이미 언급했습니다. 모니터 또는 잠금은 내부 엔티티이며 모든 오브젝트와 연관됩니다. 따라서 스레드가 객체에 액세스해야 할 때마다 먼저 객체의 잠금 또는 모니터를 획득하고 객체에 대해 작업 한 다음 잠금을 해제해야합니다.
Java의 잠금은 다음과 같습니다.
public class Lock { private boolean isLocked = false; public synchronized void lock() throws InterruptedException { while(isLocked) { wait(); } isLocked = true; } public synchronized void unlock(){ isLocked = false; notify(); } }
위와 같이 인스턴스를 잠그는 lock () 메서드가 있습니다. lock () 메서드를 호출하는 모든 스레드는 unblock () 메서드 집합이 잠금 플래그가 false로 설정되고 대기중인 모든 스레드에 알릴 때까지 차단됩니다.
잠금에 대해 기억해야 할 몇 가지 사항 :
- Java에서 각 개체에는 잠금 또는 모니터가 있습니다. 이 잠금은 스레드에서 액세스 할 수 있습니다.
- 한 번에 하나의 스레드 만이 모니터 또는 잠금을 획득 할 수 있습니다.
- Java 프로그래밍 언어는 블록이나 메소드를 Synchronized로 만들어 스레드를 동기화 할 수있는 키워드 Synchronized '를 제공합니다.
- 스레드가 액세스해야하는 공유 리소스는이 동기화 된 블록 / 방법에 보관됩니다.
자바의 뮤텍스
이미 다중 스레드 환경에서 둘 이상의 스레드가 공유 리소스에 동시에 액세스하려고 할 때 경쟁 조건이 발생할 수 있으며 경쟁 조건으로 인해 예기치 않은 출력이 발생할 수 있다고 이미 논의했습니다.
공유 리소스에 액세스를 시도하는 프로그램 부분을 '중요 섹션' . 경쟁 조건의 발생을 방지하려면 중요 섹션에 대한 액세스를 동기화해야합니다. 이 중요 섹션을 동기화하여 한 번에 하나의 스레드 만 중요 섹션에 액세스 할 수 있도록합니다.
가장 간단한 유형의 동기화 장치는 '뮤텍스'입니다. Mutex는 주어진 인스턴스에서 하나의 스레드 만 중요 섹션을 실행할 수 있도록합니다.
뮤텍스는 위에서 논의한 모니터 또는 잠금의 개념과 유사합니다. 스레드가 중요 섹션에 액세스해야하는 경우 뮤텍스를 획득해야합니다. 뮤텍스가 획득되면 스레드는 중요 섹션 코드에 액세스하고 완료되면 뮤텍스를 해제합니다.
중요 섹션에 액세스하기 위해 대기중인 다른 스레드는 그 동안 차단됩니다. 뮤텍스를 보유한 스레드가이를 해제하자마자 다른 스레드가 중요 섹션에 들어갑니다.
소프트웨어 테스트에서 자동화 테스트 란?
Java에서 뮤텍스를 구현할 수있는 방법에는 여러 가지가 있습니다.
- 동기화 된 키워드 사용
- 세마포어 사용
- ReentrantLock 사용
이 자습서에서는 첫 번째 접근 방식 즉, 동기화에 대해 설명합니다. 다른 두 가지 접근 방식 인 Semaphore와 ReentrantLock은 Java 동시 패키지에 대해 설명하는 다음 자습서에서 설명합니다.
동기화 된 키워드
Java는 프로그램에서 Critical 섹션을 표시하는 데 사용할 수있는 키워드 'Synchronized'를 제공합니다. 중요 섹션은 코드 블록 또는 완전한 방법 일 수 있습니다. 따라서 하나의 스레드 만 Synchronized 키워드로 표시된 중요 섹션에 액세스 할 수 있습니다.
Synchronized 키워드를 사용하여 애플리케이션의 동시 실행 부분 (동시에 실행되는 부분)을 작성할 수 있습니다. 또한 코드 블록이나 Synchronized 메서드를 만들어 경쟁 조건을 제거합니다.
블록 또는 메서드를 동기화 된 것으로 표시하면 이러한 엔터티 내부의 공유 리소스가 동시 액세스 및 손상으로부터 보호됩니다.
동기화 유형
아래에 설명 된대로 두 가지 유형의 동기화가 있습니다.
# 1) 프로세스 동기화
프로세스 동기화에는 여러 프로세스 또는 스레드가 동시에 실행됩니다. 궁극적으로 이러한 프로세스 또는 스레드가 특정 일련의 작업을 수행하는 상태에 도달합니다.
# 2) 스레드 동기화
스레드 동기화에서 둘 이상의 스레드가 공유 공간에 액세스하려고합니다. 스레드는 한 번에 하나의 스레드에서만 공유 공간에 액세스하는 방식으로 동기화됩니다.
프로세스 동기화는이 자습서의 범위를 벗어납니다. 따라서 여기서는 스레드 동기화 만 논의 할 것입니다.
Java에서는 다음과 함께 동기화 된 키워드를 사용할 수 있습니다.
- 코드 블록
- 방법
위의 유형은 상호 배타적 인 유형의 스레드 동기화입니다. 상호 배제는 공유 데이터에 액세스하는 스레드가 서로 간섭하지 않도록합니다.
스레드 동기화의 다른 유형은 스레드 간의 협력을 기반으로하는 'InterThread 통신'입니다. 스레드 간 통신은이 자습서의 범위를 벗어납니다.
블록과 메소드의 동기화를 진행하기 전에 동기화가 없을 때 스레드의 동작을 보여주는 Java 프로그램을 구현해 보겠습니다.
동기화없는 멀티 스레딩
다음 Java 프로그램에는 동기화되지 않은 여러 스레드가 있습니다.
class PrintCount { //method to print the thread counter public void printcounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run method for thread public void run() { PD.printcounter(); System.out.println('Thread ' + threadName + ' exiting.'); } //start method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create two instances of thread class ThreadCounter T1 = new ThreadCounter( 'ThreadCounter_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'ThreadCounter_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
산출
출력에서 스레드가 동기화되지 않았기 때문에 출력이 일관성이 없음을 알 수 있습니다. 두 스레드가 모두 시작된 다음 카운터를 차례로 표시합니다. 두 스레드 모두 끝에서 종료됩니다.
주어진 프로그램에서 첫 번째 스레드는 카운터 값을 표시 한 후 종료되어야하며 두 번째 스레드는 카운터 값을 표시하기 시작해야합니다.
이제 동기화를 시작하고 코드 블록 동기화를 시작하겠습니다.
동기화 된 코드 블록
동기화 된 블록은 코드 블록을 동기화하는 데 사용됩니다. 이 블록은 일반적으로 몇 줄로 구성됩니다. 동기화 된 블록은 전체 메서드가 동기화되는 것을 원하지 않을 때 사용됩니다.
예를 들면 75 줄의 코드를 사용하는 방법이 있습니다. 이 중에서 한 번에 한 스레드에서 실행하는 데 10 줄의 코드 만 필요합니다. 이 경우 전체 메서드를 동기화하면 시스템에 부담이됩니다. 이러한 상황에서 우리는 동기화 된 블록을 찾습니다.
동기화 된 메서드의 범위는 항상 동기화 된 메서드의 범위보다 작습니다. 동기화 된 메서드는 여러 스레드에서 사용할 공유 리소스의 개체를 잠급니다.
동기화 된 블록의 일반적인 구문은 다음과 같습니다.
synchronized (lock_object){ //synchronized code statements }
여기서 'lock_object'는 잠금을 획득 할 객체 참조 표현식입니다. 따라서 스레드가 실행을 위해 블록 내부의 동기화 된 명령문에 액세스하려고 할 때마다 'lock_object'모니터에서 잠금을 획득해야합니다.
이미 논의 된 바와 같이, 동기화 된 키워드는 한 번에 하나의 스레드 만 잠금을 획득 할 수 있고 다른 모든 스레드는 잠금을 보유한 스레드가 완료되고 잠금을 해제 할 때까지 기다려야합니다.
노트
- 사용 된 lock_object가 Null이면 'NullPointerException'이 발생합니다.
- 스레드가 잠금을 유지하는 동안 휴면 상태이면 잠금이 해제되지 않습니다. 다른 스레드는이 휴면 시간 동안 공유 객체에 액세스 할 수 없습니다.
이제 약간의 변경으로 이미 구현 된 위의 예를 보여 드리겠습니다. 이전 프로그램에서는 코드를 동기화하지 않았습니다. 이제 동기화 된 블록을 사용하고 출력을 비교합니다.
동기화를 통한 멀티 스레딩
아래의 자바 프로그램에서는 동기화 된 블록을 사용합니다. run 메서드에서 각 스레드에 대한 카운터를 인쇄하는 줄 코드를 동기화합니다.
class PrintCount { //print thread counter public void printCounter() { try { for(int i = 5; i > 0; i--) { System.out.println('Counter ==> ' + i ); } } catch (Exception e) { System.out.println('Thread interrupted.'); } } } //thread class class ThreadCounter extends Thread { private Thread t; private String threadName; PrintCount PD; //class constructor for initialization ThreadCounter( String name, PrintCount pd) { threadName = name; PD = pd; } //run () method for thread with synchronized block public void run() { synchronized(PD) { PD.printCounter(); } System.out.println('Thread ' + threadName + ' exiting.'); } //start () method for thread public void start () { System.out.println('Starting ' + threadName ); if (t == null) { t = new Thread (this, threadName); t.start (); } } } public class Main { public static void main(String args()) { PrintCount PD = new PrintCount(); //create thread instances ThreadCounter T1 = new ThreadCounter( 'Thread_1 ', PD ); ThreadCounter T2 = new ThreadCounter( 'Thread_2 ', PD ); //start both the threads T1.start(); T2.start(); // wait for threads to end try { T1.join(); T2.join(); } catch ( Exception e) { System.out.println('Interrupted'); } } }
산출
이제 동기화 된 블록을 사용하는이 프로그램의 출력은 매우 일관성이 있습니다. 예상대로 두 스레드가 모두 실행을 시작합니다. 첫 번째 스레드는 카운터 값 표시를 완료하고 종료합니다. 그런 다음 두 번째 스레드는 카운터 값을 표시하고 종료합니다.
동기화 된 방법
이 섹션에서는 동기화 된 방법에 대해 설명하겠습니다. 앞서 더 적은 수의 코드 줄로 구성된 작은 블록을 동기화 된 블록으로 선언 할 수 있음을 확인했습니다. 전체 함수가 동기화되도록하려면 메서드를 동기화 된 것으로 선언 할 수 있습니다.
메서드가 동기화되면 한 번에 하나의 스레드 만 메서드를 호출 할 수 있습니다.
동기화 된 메서드를 작성하는 일반적인 구문은 다음과 같습니다.
synchronized method_name (parameters){ //synchronized code }
동기화 된 블록과 마찬가지로 동기화 된 메서드의 경우 동기화 된 메서드에 액세스하는 스레드에서 사용할 lock_object가 필요합니다.
동기화 된 메서드의 경우 잠금 개체는 다음 중 하나 일 수 있습니다.
- 동기화 된 메서드가 정적이면 잠금 개체는‘.class’개체에 의해 제공됩니다.
- 비 정적 메서드의 경우 잠금 객체는 현재 객체 즉 'this'객체에 의해 제공됩니다.
동기화 된 키워드의 독특한 특징은 재진입이 가능하다는 것입니다. 즉, 동기화 된 메서드가 동일한 잠금을 사용하여 다른 동기화 된 메서드를 호출 할 수 있습니다. 따라서 잠금을 보유한 스레드는 다른 잠금을 획득하지 않고도 다른 동기화 된 메소드에 액세스 할 수 있습니다.
동기화 방법은 아래 예를 사용하여 설명합니다.
class NumberClass { //synchronized method to print squares of numbers synchronized void printSquares(int n) throws InterruptedException { //iterate from 1 to given number and print the squares at each iteration for (int i = 1; i <= n; i++) { System.out.println(Thread.currentThread().getName() + ' :: '+ i*i); Thread.sleep(500); } } } public class Main { public static void main(String args()) { final NumberClass number = new NumberClass(); //create thread Runnable thread = new Runnable() { public void run() { try { number.printSquares(3); } catch (InterruptedException e) { e.printStackTrace(); } } }; //start thread instance new Thread(thread, 'Thread One').start(); new Thread(thread, 'Thread Two').start(); } }
산출
위의 프로그램에서 우리는 숫자의 제곱을 인쇄하기 위해 동기화 된 방법을 사용했습니다. 수의 상한은 인수로 메소드에 전달됩니다. 그런 다음 1부터 시작하여 상한에 도달 할 때까지 각 숫자의 사각형이 인쇄됩니다.
주 함수에서 스레드 인스턴스가 생성됩니다. 각 스레드 인스턴스에는 숫자가 전달되어 사각형을 인쇄합니다.
위에서 언급했듯이 동기화 할 메서드가 정적이면 잠금 개체가 개체가 아닌 클래스에 포함됩니다. 이것은 우리가 객체가 아니라 클래스를 잠글 것이라는 것을 의미합니다. 이를 정적 동기화라고합니다.
또 다른 예가 아래에 나와 있습니다.
class Table{ //synchronized static method to print squares of numbers synchronized static void printTable(int n){ for(int i=1;i<=10;i++){ System.out.print(n*i + ' '); try{ Thread.sleep(400); }catch(Exception e){} } System.out.println(); } } //thread class Thread_One class Thread_One extends Thread{ public void run(){ Table.printTable(2); } } //thread class Thread_Two class Thread_Two extends Thread{ public void run(){ Table.printTable(5); } } public class Main{ public static void main(String t()){ //create instances of Thread_One and Thread_Two Thread_One t1=new Thread_One (); Thread_Two t2=new Thread_Two (); //start each thread instance t1.start(); t2.start(); } }
산출
위의 프로그램에서 우리는 숫자의 곱셈표를 인쇄합니다. 테이블이 인쇄 될 각 번호는 다른 스레드 클래스의 스레드 인스턴스입니다. 따라서 우리는 2와 5의 곱셈 테이블을 인쇄합니다. 그래서 우리는 각각 테이블 2와 5를 인쇄하기 위해 두 클래스의 thread_one과 thread_two를 가지고 있습니다.
요약하면 Java 동기화 된 키워드는 다음 기능을 수행합니다.
- Java의 동기화 된 키워드는 잠금 메커니즘을 제공하여 공유 자원에 대한 상호 배타적 인 액세스를 보장합니다. 잠금은 또한 경쟁 조건을 방지합니다.
- 동기화 된 키워드를 사용하여 코드에서 동시 프로그래밍 오류를 방지합니다.
- 메서드 또는 블록이 동기화 된 것으로 선언되면 스레드는 동기화 된 메서드 또는 블록에 들어가기 위해 배타적 잠금이 필요합니다. 필요한 작업을 수행 한 후 스레드는 잠금을 해제하고 쓰기 작업을 플러시합니다. 이렇게하면 불일치와 관련된 메모리 오류가 제거됩니다.
자바에서 휘발성
Java의 volatile 키워드는 클래스를 스레드로부터 안전하게 만드는 데 사용됩니다. 또한 volatile 키워드를 사용하여 다른 스레드에 의해 변수 값을 수정합니다. volatile 키워드는 객체뿐만 아니라 기본 유형으로 변수를 선언하는 데 사용할 수 있습니다.
Windows에서 swf 파일을 재생하는 방법
어떤 경우에는 volatile 키워드가 동기화 된 키워드의 대안으로 사용되지만 동기화 된 키워드를 대체하는 것은 아닙니다.
변수가 휘발성으로 선언되면 해당 값은 캐시되지 않고 항상 주 메모리에서 읽습니다. 휘발성 변수는 순서와 가시성을 보장합니다. 변수를 휘발성으로 선언 할 수 있지만 클래스 나 메서드를 휘발성으로 선언 할 수 없습니다.
다음 코드 블록을 고려하십시오.
class ABC{ static volatile int myvar =10; }
위 코드에서 myvar 변수는 정적이며 휘발성입니다. 정적 변수는 모든 클래스 개체간에 공유됩니다. 휘발성 변수는 항상 주 메모리에 상주하며 캐시되지 않습니다.
따라서 주 메모리에는 myvar의 복사본이 하나만 있으며 모든 읽기 / 쓰기 작업은 주 메모리에서이 변수에 대해 수행됩니다. myvar가 휘발성으로 선언되지 않은 경우 각 스레드 객체는 불일치를 초래하는 다른 복사본을 갖게됩니다.
Volatile 및 Synchronized 키워드의 차이점 중 일부는 다음과 같습니다.
휘발성 키워드 | 동기화 된 키워드 |
---|---|
volatile 키워드는 변수에만 사용됩니다. | 동기화 된 키워드는 코드 블록 및 메서드와 함께 사용됩니다. |
volatile 키워드는 대기중인 스레드를 차단할 수 없습니다. | 동기화 된 키워드는 대기중인 스레드를 차단할 수 있습니다. |
Volatile을 사용하면 스레드 성능이 향상됩니다. | 스레드 성능은 동기화로 인해 다소 저하됩니다. |
휘발성 변수는 주 메모리에 있습니다. | 동기화 된 구조는 주 메모리에 상주하지 않습니다. |
Volatile은 스레드 메모리와 주 메모리간에 한 번에 하나의 변수를 동기화합니다. | Synchronized 키워드는 모든 변수를 한 번에 동기화합니다. |
자바의 교착 상태
동기화 된 키워드를 사용하여 여러 스레드를 동기화하고 프로그램을 스레드로부터 안전하게 만들 수 있음을 확인했습니다. 스레드를 동기화하여 다중 스레드 환경에서 여러 스레드가 동시에 실행되도록합니다.
그러나 때때로 스레드가 더 이상 동시에 작동 할 수없는 상황이 발생합니다. 대신 그들은 끝없이 기다립니다. 이것은 한 스레드가 리소스를 대기하고 해당 리소스가 두 번째 스레드에 의해 차단 될 때 발생합니다.
반면에 두 번째 스레드는 첫 번째 스레드에 의해 차단 된 리소스를 기다리고 있습니다. 이러한 상황은 Java에서 '교착 상태'를 유발합니다.
Java의 교착 상태는 아래 이미지를 사용하여 설명됩니다.
위의 다이어그램에서 볼 수 있듯이 스레드 A는 리소스 r1을 잠그고 리소스 r2를 기다리고 있습니다. 반면 스레드 B는 r2 자원을 차단하고 r1에서 대기 중입니다.
따라서 보류중인 리소스를 확보하지 않는 한 스레드는 실행을 완료 할 수 없습니다. 이 상황으로 인해 두 스레드가 리소스를 끝없이 기다리고있는 교착 상태가 발생했습니다.
다음은 Java에서 교착 상태의 예입니다.
public class Main { public static void main(String() args) { //define shared resources final String shared_res1 = 'Java tutorials'; final String shared_res2 = 'Multithreading'; // thread_one => locks shared_res1 then shared_res2 Thread thread_one = new Thread() { public void run() { synchronized (shared_res1) { System.out.println('Thread one: locked shared resource 1'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res2) { System.out.println('Thread one: locked shared resource 2'); } } } }; // thread_two=> locks shared_res2 then shared_res1 Thread thread_two = new Thread() { public void run() { synchronized (shared_res2) { System.out.println('Thread two: locked shared resource 2'); try { Thread.sleep(100);} catch (Exception e) {} synchronized (shared_res1) { System.out.println('Thread two: locked shared resource 1'); } } } }; //start both the threads thread_one.start(); thread_two.start(); } }
산출
위의 프로그램에는 두 개의 공유 리소스와 두 개의 스레드가 있습니다. 두 스레드 모두 공유 리소스에 하나씩 액세스하려고합니다. 출력에는 다른 스레드를 기다리는 동안 각각 하나의 리소스를 잠그는 두 스레드가 모두 표시됩니다. 이로 인해 교착 상태가 발생합니다.
교착 상태 상황이 완전히 발생하는 것을 막을 수는 없지만 몇 가지 조치를 취하면 확실히 피할 수 있습니다.
아래에 나열된 것은 Java에서 교착 상태를 피할 수있는 방법입니다.
# 1) 중첩 된 잠금을 피함으로써
중첩 된 잠금이 교착 상태를 갖는 가장 중요한 이유입니다. 중첩 잠금은 여러 스레드에 제공되는 잠금입니다. 따라서 우리는 둘 이상의 스레드에 잠금을 제공하지 않아야합니다.
# 2) 스레드 조인 사용
스레드가 최대 실행 시간을 사용할 수 있도록 Thread.join을 최대 시간으로 사용해야합니다. 이렇게하면 한 스레드가 다른 스레드를 계속 대기 할 때 주로 발생하는 교착 상태가 방지됩니다.
# 3) 불필요한 잠금 방지
필요한 코드 만 잠 가야합니다. 코드에 대해 불필요한 잠금이 있으면 프로그램에서 교착 상태가 발생할 수 있습니다. 교착 상태는 코드를 깨고 프로그램의 흐름을 방해 할 수 있으므로 프로그램에서 교착 상태를 피하는 경향이 있습니다.
자주 묻는 질문
Q # 1) 동기화 란 무엇이며 왜 중요한가요?
대답: 동기화는 여러 스레드에 대한 공유 리소스의 액세스를 제어하는 프로세스입니다. 동기화가 없으면 여러 스레드가 공유 리소스를 동시에 업데이트하거나 변경하여 불일치를 초래할 수 있습니다.
따라서 다중 스레드 환경에서 스레드가 동기화되어 공유 리소스에 액세스하는 방식이 상호 배타적이고 일관성이 있도록해야합니다.
Q # 2) Java에서 동기화 및 비동기 화란 무엇입니까?
대답: 동기화는 구문이 스레드로부터 안전함을 의미합니다. 이는 여러 스레드가 한 번에 구성 (코드 블록, 메소드 등)에 액세스 할 수 없음을 의미합니다.
동기화되지 않은 구문은 스레드로부터 안전하지 않습니다. 여러 스레드는 언제든지 동기화되지 않은 메서드 또는 블록에 액세스 할 수 있습니다. Java에서 인기있는 동기화되지 않은 클래스는 StringBuilder입니다.
Q # 3) 동기화가 필요한 이유는 무엇입니까?
대답: 프로세스를 동시에 실행해야하는 경우 동기화가 필요합니다. 많은 프로세스간에 공유 할 수있는 리소스가 필요하기 때문입니다.
공유 리소스에 액세스하기위한 프로세스 또는 스레드 간의 충돌을 방지하려면 모든 스레드가 리소스에 액세스하고 응용 프로그램도 원활하게 실행되도록 이러한 리소스를 동기화해야합니다.
Q # 4) Synchronized ArrayList는 어떻게 얻습니까?
대답: ArrayList를 인수로 사용하여 Collections.synchronized list 메서드를 사용하여 ArrayList를 동기화 된 목록으로 변환 할 수 있습니다.
Q # 5) HashMap이 동기화되어 있습니까?
여러 YouTube 비디오를 mp3로 변환
대답: 아니요, HashMap은 동기화되지 않지만 HashTable은 동기화됩니다.
결론
이 자습서에서는 스레드 동기화에 대해 자세히 설명했습니다. 이와 함께 Java의 volatile 키워드 및 교착 상태에 대해서도 배웠습니다. 동기화는 프로세스 및 스레드 동기화로 구성됩니다.
멀티 스레딩 환경에서 우리는 스레드 동기화에 더 관심이 있습니다. 여기서는 스레드 동기화의 동기화 된 키워드 접근 방식을 보았습니다.
교착 상태는 여러 스레드가 자원을 끝없이 기다리는 상황입니다. Java에서 교착 상태를 방지하는 방법과 함께 Java에서 교착 상태의 예를 보았습니다.
=> 처음부터 Java를 배우려면 여기를 방문하십시오.