线程交互
盖伦持续掉血,但是血量到达1的时候,不能继续掉了,因为血量不能为负。只有等待回复血量,再进行减血操作,这个时候就有两个线程在操作这个英雄的hp,这两个线程操作的过程就是交互。减血线程到1时,等待加血线程加血wait,加血之后,唤醒减血线程notify。这样完成两个线程的交互。
交互流程图
wait是线程等待的意思,将当前线程推出cpu,把唤醒(notify)的线程放入cpu执行完,然后再执行之前wait的线程。如果notifyall唤醒所有线程,那么这所有唤醒的线程,就进行抢占cpu,谁抢到谁去执行。
示例代码
在具体的业务代码中,去指定那个方法该等待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(); } }
效果