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();
}
}
실행 결과는 다음과 같습니다.