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();

    }
}

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

 

Supongo que te gusta

Origin blog.csdn.net/m0_71385552/article/details/128460050
Recomendado
Clasificación