线程交互
盖伦持续掉血,但是血量到达1的时候,不能继续掉了,因为血量不能为负。只有等待回复血量,再进行减血操作,这个时候就有两个线程在操作这个英雄的hp,这两个线程操作的过程就是交互。减血线程到1时,等待加血线程加血wait,加血之后,唤醒减血线程notify。这样完成两个线程的交互。
交互流程图
wait是线程等待的意思,将当前线程推出cpu,把唤醒(notify)的线程放入cpu执行完,然后再执行之前wait的线程。如果notifyall唤醒所有线程,那么这所有唤醒的线程,就进行抢占cpu,谁抢到谁去执行。
![](https://i-blog.csdnimg.cn/blog_migrate/a581767628396aeb343aaa37efb5e5a5.png)
示例代码
在具体的业务代码中,去指定那个方法该等待wait,哪个该notify唤醒。Hero.java
package com.thread.thread15;
public class Hero {
public String name; //英雄名字
public float hp; //血量
public int damage; //攻击力
//回复血量
public synchronized void recover() {
hp = hp + 1;
System.out.printf("%s 回血一点后, %s的血量是%.0f%n", name, name, hp);
//通知那些等待的this对象上的线程 可以醒过来了 如第20行 等待着减血线程苏醒过来
this.notify();
}
//减少血量
public synchronized void hurt() {
if(hp==1) {
try {
//让占有this的减血线程 暂时释放对this的占有 并等待
this.wait();
}catch (InterruptedException e) {
e.printStackTrace();
}
}
hp = hp - 1;
System.out.printf("%s 减血1点 ,减少血后, %s的血量是%.0f%n", name, name, hp );
}
//攻击手段
public void attackHero(Hero h) {
h.hp -= damage; //每次攻击 英雄都会损失相应血量
//%s对应的字符串变量
//%.f 血量float
System.out.printf("%s 正在攻击 %s, %s的血变成了 %.0f%n", name, h.name, h.name, h.hp);
if(h.isDead()) {
System.out.println(h.name + "死了!");
}
}
//判断英雄是否死亡
public boolean isDead(){
return 0>=hp?true:false; // 如果血量 小于0 则isDead=true 血量大于0 则isDead=false 没有死
}
}
测试类中,创建两个线程启动。当然在线程内部,可以用具体的代码逻辑来代替线程的交互操作,但是会消耗大量的cpu,所以使用这样的交互过程
package com.thread.thread15;
public class TestThread {
public static void main(String[] args) {
final Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 100;
Thread t1 = new Thread() {
public void run() {
while(true) {
//因为减少血量更快 所以盖伦的血量迟早会到达1
//使用while循环判断是否1 如果1的话不停的循环
//直到加血线程回复了血量
// while(gareen.hp == 1) {
// continue;
// }
gareen.hurt();
// System.out.printf("t1 为 %s 减血1点,减少血后,%s的血量是%.0f%n", gareen.name, gareen.name,gareen.hp);
try {
Thread.sleep(10);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
Thread t2 = new Thread(){
public void run() {
while(true) {
gareen.recover();
// System.out.printf("t2 为%s回血1点,增加血量后,%s的血量是%.0f%n", gareen.name, gareen.name, gareen.hp);
try{
Thread.sleep(100);
}catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t2.start();
}
}
效果
![](https://i-blog.csdnimg.cn/blog_migrate/25fad1f664ff44ea05a45ab7298ff35b.png)