Java의 스레드 간 통신 메커니즘(깨우기 메커니즘 대기)

1. 스레드 간 통신

1. 개요

        여러 스레드가 동일한 리소스를 처리하고 있지만 처리 작업(스레드 작업)이 다릅니다.

예: 스레드 A는 찐빵을 생산하는 데 사용되고 스레드 B는 찐빵을 먹는 데 사용되며 찐빵은 동일한 리소스인 스레드 A로 이해될 수 있습니다.

스레드 B가 처리하는 작업 중 하나는 생산이고 다른 하나는 소비이므로 스레드 A와 스레드 B 간의 스레드 통신 문제가 있습니다.

 2. 왜 스레드 통신을 다루어야 합니까?

        여러 스레드가 동시에 실행될 때 CPU는 기본적으로 스레드를 무작위로 전환합니다. 작업을 함께 완료하기 위해 여러 스레드가 필요하고 정기적으로 실행하기를 원하는 경우 여러 스레드 간에 조정된 통신이 필요합니다. 이는 멀티스레딩을 달성하는 데 도움이 됩니다. 하나의 데이터를 공동으로 운영합니다.

3. 스레드 간 통신이 리소스를 효과적으로 활용하도록 보장하는 방법

        여러 스레드가 동일한 리소스를 처리하고 다른 작업을 수행하는 경우 스레드 간 동일한 변수의 사용이나 연산을 해결하는 데 도움이 되는 스레드 통신이 필요합니다.즉, 여러 스레드가 동일한 데이터를 운영할 때 동일한 공유 변수를 두고 경쟁하는 것을 피할 수 있습니다. ... 즉, 각 스레드가 리소스를 효과적으로 활용할 수 있도록 특정 수단을 사용해야 합니다. 이 방법을 "대기 깨우기 메커니즘"이라고 합니다.

2. 깨우기 메커니즘을 기다리는 중

1. 컨셉

대기 중인 깨우기 메커니즘은 여러 스레드 간의협력 메커니즘입니다.

스레드가 지정된 작업을 완료하면 대기 상태(wait())로 들어가 다른 스레드가 해당 작업을 완료할 때까지 기다립니다. . 그런 다음 깨우세요(notify(); 대기 중인 스레드가 여러 개인 경우에는 informAll()을 사용하여 대기 중인 모든 스레드를 깨울 수 있습니다.notify(). a>; a>notify()

2. 사용방법

2.1  잠깐만요

wait: 스레드를 더 이상 활성 상태로 만들고 더 이상 스케줄링에 참여하지 않게 하며, 다른 스레드가 inform 또는 informAll을 실행하여 대기 세트에서 해제하고 스케줄링 큐(준비 큐)에 다시 들어갈 때까지 대기 큐(대기 세트)에 들어갑니다.

2.2 통지

알림: 대기 설정 스레드를 선택하여 해제합니다. 예를 들어 레스토랑에 빈 자리가 생기면 가장 오랫동안 기다린 고객이 먼저 자리에 앉게 됩니다.

지침:

1. 통지에 의해 해제된 스레드는 원래 동기화된 블록에서 중단되었고 더 이상 잠금을 보유하지 않기 때문에 즉시 실행을 재개할 수 없으므로 잠금을 다시 획득하려고 시도해야 합니다(대부분 다른 스레드와 경쟁에 직면할 가능성이 높음). , 원래 wait 메소드가 호출된 이후부터 실행을 재개할 수 있습니다.

요약하면 다음과 같습니다. Lock을 획득할 수 있으면 스레드는 WAITING 상태에서 RUNNABLE 상태로 변경되고, 그렇지 않으면 대기 세트에서 나온 후 WAITING 상태에서 BLOCKED 상태로 변경됩니다. 다시 상태
2. wait 메소드와 통지 메소드는 동일한 잠금 객체에 의해 호출되어야 합니다.
3. wait 메소드와 inform 메소드는 동기화된 코드 블록이나 동기화된 함수에서 사용해야 한다. 이 두 메소드는 lock 객체를 통해 호출되어야 하기 때문이다.
4. wait 메소드와 inform 메소드는 Object 클래스에 속하며, lock 객체는 어떤 객체라도 될 수 있으며, 객체가 속한 클래스는 Object 클래스를 상속받습니다.

3. 생산자와 소비자

롤빵 유형:

public class BaoZi {
    //包子名
    String name;
    //包子状态
    boolean flag;
}

미식가 카테고리:

/**
 * 消费者模型
 */
public class ChiHuo extends Thread{
    //资源对象
    BaoZi baozi;

    //定义构造方法:给线程定义名字,同时给BaoZi对象赋值
    public ChiHuo(String threadName,BaoZi bz){
        super(threadName);
        this.baozi=bz;
    }
    /**
     * 吃货线程的功能:
     *      如果包子不存在,线程进入等待状态
     *      如果包子存在,  线程开始吃包子,吃完后更改包子的状态变为不存在,唤醒早餐点线程开始制作包子
     */
    @Override
    public void run() {
        //获取线程的名字
        String threadName = Thread.currentThread().getName();
        for (int i = 0; i < 10; i++) {
            synchronized (baozi){
                if (baozi.flag){//包子存在
                    System.out.println(threadName+"正在吃"+baozi.name);//吃包子
                    baozi.flag=false;//更改包子状态
                    baozi.notify();  //唤醒同一资源下的其他线程
                }else {//包子不存在
                    try {
                        baozi.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
}

아침 식사 레스토랑 카테고리:

/**
 * 生产者模型
 */
public class ZaoCanDian extends Thread{
    //资源对象
    BaoZi baoZi;

    //定义构造方法:给线程定义名字,同时给BaoZi对象赋值
    public ZaoCanDian(String threadName,BaoZi bz){
        super(threadName);
        this.baoZi=bz;
    }

    /**
     * 早餐店线程的功能:
     *      如果包子存在,线程进入等待状态
     *      如果包子不存在,  线程开始制作包子,制作完毕更改包子的状态为存在,唤醒吃货线程吃包子
     */
    @Override
    public void run() {
        //获取线程的名字
        String threadName = Thread.currentThread().getName();
        for (int i = 0; i < 10; i++) {
            synchronized (baoZi){
                if (baoZi.flag){//包子存在
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }else {//包子不存在
                    System.out.println(threadName+"制作"+baoZi.name);//制作包子
                    baoZi.flag=true;//更改包子状态
                    baoZi.notify(); //唤醒同一资源下的其他线程
                }
            }
        }
    }
}

테스트 클래스:

public class ThreadTest01 {
    public static void main(String[] args) {
        //实例化包子对象
        BaoZi bz = new BaoZi();
        //赋值
        bz.name="鲜肉包";
        bz.flag=false;

        //实例化ChiHuo和ZaoCanDian线程对象
        ChiHuo ch =new ChiHuo("猪八戒",bz);
        ZaoCanDian zcd = new ZaoCanDian("春光早餐",bz);

        //启动线程
        ch.start();
        zcd.start();

    }
}

실행 결과는 다음과 같습니다.

 

추천

출처blog.csdn.net/m0_71385552/article/details/128460050