자바 멀티 스레딩 (3 개) --- 동기화 및 교착 상태

질문의 기원 :

예를 들어 기차표 판매를 예로 들어 보자. 지금 기차표를 사고 싶다면 기차역이나 다양한 온라인 매표소에 갈 수있다. 그러나 기차표를 판매 할 곳이 얼마나 많든간에 기차 수는 티켓은 고정되어 있습니다. 모든 티켓 아울렛은 동일한 기차 티켓을 공유해야합니다. 티켓 포인트가 스레드에 비유되면 모든 스레드는 시간에 따라 프로세스 리소스를 공유합니다.

코드 구현 :

class MyThread1 implements Runnable{
	private int ticket=5;
	public void run() {
		for(int i=0;i<100;i++) {
			if(ticket>0) {
				System.out.println("卖第"+ticket--+"张票");}}}}
public class TongBu {
	public static void main(String[] args) {
		MyThread1 mThread1=new MyThread1();
		Thread t1=new Thread(mThread1);
		Thread t2=new Thread(mThread1);
		Thread t3=new Thread(mThread1);
		t1.start();
		t2.start();
		t3.start();}}

작업 결과 :
영상

그러나 실제 응용 프로그램에서는 데이터가 데이터베이스에 저장되고 사용자 주문 정보도 데이터베이스에 저장됩니다. 즉, 데이터를 데이터베이스에 저장하는 데 일정 시간이 걸립니다. 여기서 네트워크 지연을 시뮬레이션합니다. .

구현 코드 :

class MyThread1 implements Runnable{
	private int ticket=5;
	public void run() {
		for(int i=0;i<100;i++) {
			if(ticket>0) {
				System.out.println("卖第"+ticket--+"张票");
				try {
					Thread.sleep(500);
				} catch (Exception e) {
					// TODO: handle exception}}}}}
public class TongBu {
	public static void main(String[] args) {
		MyThread1 mThread1=new MyThread1();
		Thread t1=new Thread(mThread1);
		Thread t2=new Thread(mThread1);
		Thread t3=new Thread(mThread1);
		t1.start();
		t2.start();
		t3.start();}}

실행 결과를 살펴 보겠습니다.
영상

티켓 매수가 반복적으로 팔리고 있고, 프로그램 코드에 문제가있어 사용자 간 충돌이 발생하는 것을 확인할 수 있습니다.

왜 그런 현상이 있습니까?

여기서는 오퍼레이션 코드의 구현 단계를 간단히 분석해 보겠습니다.
여기에 사진 설명 삽입

여기서 스레드 1이 리소스의 데이터를 꺼내 마이너스 1 연산을 수행 한 다음 다시 넣는 것을 볼 수 있습니다. 여기서 숫자를 반복하는 이유는 스레드 1이 리소스를 꺼낼 때 스레드 2도 해당 데이터를 꺼내기 때문입니다. 예를 들어, 쓰레드 1이 그것을 꺼내고, 쓰레드 1이 나가기 전에는 3이었고, 쓰레드 1이 나간 이후의 숫자는 3이었습니다. 그러나 네트워크 지연 때문에 쓰레드 1이 방금 꺼내지고 처리되지 않았을 때 , 스레드 2 페이지가 동시에 리소스 3을 꺼 냈습니다.이 때 스레드 1과 스레드 2가 데이터를 얻었습니다. 둘 다 3입니다. 이때 스레드 1은 2로 계산하고 2를 출력하고 스레드 2는 2로 계산하여 출력합니다. 2, 그래서 반복되는 숫자가 생성됩니다.

이 문제를 해결하는 방법?

이러한 문제를 해결하려면 동기화를 사용해야합니다. 동기화라고하는 것은 여러 작업을 동일한 시간에 한 스레드에서만 수행 할 수 있고 다른 스레드는 계속하기 전에이 스레드가 완료 될 때까지 기다려야 함을 의미합니다. 즉, 스레드 1이 실행되는 동안 즉, 스레드 1이 데이터를 가져온 후 스레드 2는 동기 잠금 인 리소스 변수에서 작동 할 수 없습니다.

영상

동기화

리소스 공유의 동기화 작업 문제를 해결하기 위해 동기화 코드 블록 및 동기화 방법을 사용하여 완료 할 수 있습니다.

동기화 코드 블록

코드 블록은 네 가지 유형의 코드 블록으로 나뉩니다.

  • 공통 코드 블록 : 메서드에 직접 정의 된 코드 블록입니다.
  • 빌딩 블록 : 클래스에서 직접 정의되며 생성 방법 이전에 실행되며 반복적으로 호출 할 수 있습니다.
  • Static fast : 빌딩 블록 실행보다 우선하며 한 번만 실행되는 static 키워드를 사용하여 선언됩니다.
  • 동기화 된 코드 블록 : 동기화 된 키워드로 선언 된 코드 블록을 동기화 된 코드 블록이라고합니다.

정의 형식 :

sync (동기화 객체) {

동기화 및 잠금이 필요한 코드}

일반적으로 현재 객체는 동기화 된 객체로 간주되며 이것으로 표현됩니다.

public void run() {
		for(int i=0;i<100;i++) {
			synchronized (this) {			
			if(ticket>0) {				
				try {
					Thread.sleep(500);
				} catch (Exception e) {
					// TODO: handle exception
				}
				System.out.println("卖第"+ticket--+"张票");
			}}

프로그램은 단계적으로 실행되지만 속도는 감소합니다.
동기화 방법

메서드 반환 값 전에 동기화를 추가합니다.

형식은 동기화 메소드 반환 값 메소드 이름 (매개 변수 목록) {}입니다.

이중 자물쇠

프로그램이 너무 많으면 교착 상태가 발생합니다.

동기화는 교착 상태의 전제 조건입니다. 예를 들어 두 개의 스레드가 있습니다. 스레드 A는 실행하려면 스레드 B의 리소스가 필요하고 스레드 B는 실행하는 데 스레드 A의 리소스도 필요합니다. 항상 상대방이 제거하기를 기다리고 있습니다. 교착 상태라고하는 자원.

멀티 스레딩 및 멀티 프로세싱은 시스템 자원의 활용도를 높이고 시스템의 처리 용량을 증가 시키지만 동시에 실행하면 새로운 문제 교착 상태가 발생합니다. 소위 교착 상태는 자원을 놓고 경쟁하는 여러 스레드로 인해 발생하는 교착 상태 (서로를 기다리는 것)를 말하며, 외부 힘이 없으면 이러한 프로세스는 앞으로 나아갈 수 없습니다.

소위 교착 상태는 실행 과정에서 자원 경쟁으로 인해 두 개 이상의 스레드가 서로를 기다리는 현상을 말하며 외부의 힘이 없으면 전진 할 수 없습니다.

아래에서는 교착 상태 현상을 설명하기 위해 예제를 사용합니다.

두 사람이 단일 판자 다리를 마주 보며 건너고 있습니다. A와 B는 이미 다리 위의 거리, 즉 다리의 자원을 차지하고 있습니다. A가 단일 판자 다리를 통과하려면 B는 반드시 밖으로 나가야합니다. 교량 자원을 내보내고 A는 통과하지만 B 아니오, B는 여전히 먼저 가고 싶어하므로 A와 B가 모두 교착 상태가됩니다.

영상

교착 상태에 필요한 조건 :

교착 상태 생성에는 네 가지 조건이 필수이며 상속을 기반으로 다형성을 생성해야하는 것과 유사합니다.

  • 상호 배타적 조건 : 프로세스에는 할당 된 리소스 (예 : 프린터)에 대한 배타적 인 제어가 필요합니다. 즉, 특정 리소스는 일정 시간 내에 한 프로세스에서만 점유 할 수 있습니다. 이때 다른 프로세스가 리소스를 요청하면 요청 된 프로세스는 대기만 할 수 있습니다.
  • 비 박탈 조건 : 프로세스에 의해 획득 된 리소스는 사용되기 전에 다른 프로세스에 의해 강제로 제거 될 수 없습니다. 즉, 리소스를 획득 한 프로세스에 의해서만 해제 될 수 있습니다 (수동적으로가 아니라 능동적으로 만).
  • 요청 및 보유 조건 : 프로세스가 하나 이상의 자원을 보유하고 있지만 새 자원 요청을 작성했으며 자원이 다른 프로세스에 의해 점유되었습니다. 이때 요청 프로세스는 차단되지만 획득 한 자원은 차단되지 않습니다. 석방됩니다.

순환 대기 조건 : 프로세스 자원의 순환 대기 체인이 있고 체인의 각 프로세스에서 얻은 자원은 체인의 다음 프로세스에서 동시에 요청하며 대기 상태의 프로세스 세트가 있습니다. p1 , p2 ... pn}, Pi를 기다리는 자원은 P (i + 1) (i = 0, 1,…, n-1)가 차지하고 Pn을 기다리는 자원은 다음과 같이 P0이 차지합니다. 그림 1.

직관적으로 루프 대기 조건은 교착 상태의 정의와 동일 해 보이지만 그렇지 않습니다. 교착 상태의 정의에 따르면 대기 루프를 형성하는 데 필요한 조건이 더 엄격하여 Pi가 대기하는 자원이 P (i + 1)에 의해 충족되어야하며 순환 대기 조건에는 이러한 제한이 없습니다. 예를 들어, 시스템에 두 개의 출력 장치가 있습니다. P0이 하나를 차지하고 PK가 다른 하나를 차지하며 K가 {0, 1,…, n} 집합에 속하지 않습니다.

  • Pn은 출력 장치를 기다립니다. P0 또는 PK에서 얻을 수 있습니다. 따라서 Pn, P0 등 일부 프로세스가 원형 대기 원을 형성하더라도 PK는 원 안에 있지 않으며 PK가 출력 장치를 해제하면 그림 2-16과 같이 순환 대기가 끊어 질 수 있습니다. 따라서 순환 대기는 교착 상태에 필요한 조건 일뿐입니다.

영상

교착 상태를 피하는 방법?

  • 교착 상태를 파괴하는 네 가지 주요 조건 중 하나
  • 잠금 순서 (스레드가 특정 순서로 잠김)
  • 잠금 시간 제한 (스레드가 잠금을 획득하려고 할 때 특정 시간 제한이 추가되고 시간 제한이 초과되면 잠금 요청이 취소되고 소유 한 잠금이 해제 됨)
  • 교착 상태 감지

추천

출처blog.csdn.net/qq_44762290/article/details/112379636