how2j.cn


工具版本兼容问题
线程之间有交互通知的需求,考虑如下情况:
有两个线程,处理同一个英雄。
一个加血,一个减血。

减血的线程,发现血量=1,就停止减血,直到加血的线程为英雄加了血,才可以继续减血


本视频是解读性视频,所以希望您已经看过了本知识点的内容,并且编写了相应的代码之后,带着疑问来观看,这样收获才多。 不建议一开始就观看视频



16分9秒
本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)



步骤 1 : 不好的解决方式   
步骤 2 : 使用wait和notify进行线程交互   
步骤 3 : 关于wait、notify和notifyAll   
步骤 4 : 练习-线程交互   
步骤 5 : 答案-线程交互   
步骤 6 : 练习-多线程交互   
步骤 7 : 答案-多线程交互   
步骤 8 : 练习-生产者消费者问题   
步骤 9 : 答案-生产者消费者问题   

步骤 1 :

不好的解决方式

edit
故意设计减血线程频率更高,盖伦的血量迟早会到达1
减血线程中使用while循环判断是否是1,如果是1就不停的循环,直到加血线程回复了血量
这是不好的解决方式,因为会大量占用CPU,拖慢性能
package charactor; public class Hero{ public String name; public float hp; public int damage; public synchronized void recover(){ hp=hp+1; } public synchronized void hurt(){ hp=hp-1; } public void attackHero(Hero h) { h.hp-=damage; System.out.format("%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; } }
package multiplethread; import java.awt.GradientPaint; import charactor.Hero; public class TestThread { public static void main(String[] args) { final Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 616; 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) { // TODO Auto-generated catch block 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) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; t2.start(); } }
步骤 2 :

使用wait和notify进行线程交互

edit
在Hero类中:hurt()减血方法:当hp=1的时候,执行this.wait().
this.wait()表示 让占有this的线程等待,并临时释放占有
进入hurt方法的线程必然是减血线程,this.wait()会让减血线程临时释放对this的占有。 这样加血线程,就有机会进入recover()加血方法了


recover() 加血方法:增加了血量,执行this.notify();
this.notify() 表示通知那些等待在this的线程,可以苏醒过来了。 等待在this的线程,恰恰就是减血线程。 一旦recover()结束, 加血线程释放了this,减血线程,就可以重新占有this,并执行后面的减血工作。
使用wait和notify进行线程交互
package charactor; public class Hero { public String name; public float hp; public int damage; public synchronized void recover() { hp = hp + 1; System.out.printf("%s 回血1点,增加血后,%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) { // TODO Auto-generated catch block e.printStackTrace(); } } hp = hp - 1; System.out.printf("%s 减血1点,减少血后,%s的血量是%.0f%n", name, name, hp); } public void attackHero(Hero h) { h.hp -= damage; System.out.format("%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; } }
package multiplethread; import java.awt.GradientPaint; import charactor.Hero; public class TestThread { public static void main(String[] args) { final Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 616; Thread t1 = new Thread(){ public void run(){ while(true){ //无需循环判断 // while(gareen.hp==1){ // continue; // } gareen.hurt(); try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; t1.start(); Thread t2 = new Thread(){ public void run(){ while(true){ gareen.recover(); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; t2.start(); } }
步骤 3 :

关于wait、notify和notifyAll

edit
留意wait()和notify() 这两个方法是什么对象上的?


public synchronized void hurt() {
。。。
this.wait();
。。。
}


public synchronized void recover() {
。。。
this.notify();
}


这里需要强调的是,wait方法和notify方法,并不是Thread线程上的方法,它们是Object上的方法。

因为所有的Object都可以被用来作为同步对象,所以准确的讲,wait和notify是同步对象上的方法。

wait()的意思是: 让占用了这个同步对象的线程,临时释放当前的占用,并且等待。 所以调用wait是有前提条件的,一定是在synchronized块里,否则就会出错。

notify() 的意思是,通知一个等待在这个同步对象上的线程,可以苏醒过来了,有机会重新占用当前对象了。

notifyAll() 的意思是,通知所有的等待在这个同步对象上的线程,你们可以苏醒过来了,有机会重新占用当前对象了。
步骤 4 :

练习-线程交互

edit Or  姿势不对,事倍功半! 点击查看做练习的正确姿势
假设加血线程运行得更加频繁,英雄的最大血量是1000

设计加血线程和减血线程的交互,让回血回满之后,加血线程等待,直到有减血线程减血
步骤 5 :

答案-线程交互

edit
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看本答案会花费4个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
查看本答案会花费4个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
账号未激活 账号未激活,功能受限。 请点击激活
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频

3分11秒 本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)


package charactor; public class Hero { public String name; public float hp; public int damage; public synchronized void recover() { //当血量大于或者等于1000的时候 //this.wait() 让占用这个对象的线程等待,并临时释放锁 if(hp>=1000){ try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } hp = hp + 1; System.out.printf("%s 回血1点,增加血后,%s的血量是%.0f%n", name, name, hp); this.notify(); } public synchronized void hurt() { if (hp == 1) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } hp = hp - 1; System.out.printf("%s 减血1点,减少血后,%s的血量是%.0f%n", name, name, hp); //掉血之后,唤醒等待的线程 this.notify(); } public void attackHero(Hero h) { h.hp -= damage; System.out.format("%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; } }
package multiplethread; import charactor.Hero; public class TestThread { public static void main(String[] args) { final Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 616; Thread t1 = new Thread(){ public void run(){ while(true){ gareen.hurt(); try { //减慢掉血的速度 Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; t1.start(); Thread t2 = new Thread(){ public void run(){ while(true){ gareen.recover(); try { //加快回血的速度 Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; t2.start(); } }
步骤 6 :

练习-多线程交互

edit Or  姿势不对,事倍功半! 点击查看做练习的正确姿势
在上面的练习的基础上,增加回血线程到2条,减血线程到5条,同时运行。

运行一段时间,观察会发生的错误,分析错误原因,并考虑解决办法
步骤 7 :

答案-多线程交互

edit
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看本答案会花费4个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
查看本答案会花费4个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
账号未激活 账号未激活,功能受限。 请点击激活
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频

9分55秒 本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)


在目前的状态下,会导致英雄的血量变为负数。 这是因为减血线程调用hurt() 方法结束时,调用notify,有可能会唤醒另一个减血线程,这就导致不停的减血。

解决办法是: 减血线程被唤醒后,要再次查看当前血量,如果当前血量<=1,那么就继续等待

//把if改为while,被唤醒后,会重复查看hp的值,只有hp大于1,才会往下执行


//把if改为while,被唤醒后,会重复查看hp的值,只有hp大于1,才会往下执行
//if(hp <= 1) {
while (hp <= 1) {
try {
this.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
答案-多线程交互
package charactor; public class Hero { public String name; public float hp; public int damage; public synchronized void recover() { //当血量大于或者等于1000的时候 //this.wait() 让占用这个对象的线程等待,并临时释放锁 while(hp>=1000){ try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } hp = hp + 1; System.out.printf("%s 回血1点,增加血后,%s的血量是%.0f%n", name, name, hp); this.notify(); } public synchronized void hurt() { //把if改为while,被唤醒后,会重复查看hp的值,只有hp大于1,才会往下执行 //if (hp <= 1) { while (hp <= 1) { try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } hp = hp - 1; System.out.printf("%s 减血1点,减少血后,%s的血量是%.0f%n", name, name, hp); //掉血之后,唤醒等待的线程 this.notify(); } public void attackHero(Hero h) { h.hp -= damage; System.out.format("%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; } }
package multiplethread; import charactor.Hero; public class TestThread { static class HurtThread extends Thread{ private Hero hero; public HurtThread(Hero hero){ this.hero = hero; } public void run(){ while(true){ hero.hurt(); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } static class RecoverThread extends Thread{ private Hero hero; public RecoverThread(Hero hero){ this.hero = hero; } public void run(){ while(true){ hero.recover(); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } public static void main(String[] args) { final Hero gareen = new Hero(); gareen.name = "盖伦"; gareen.hp = 616; for (int i = 0; i < 2; i++) { new RecoverThread(gareen).start(); } for (int i = 0; i < 5; i++) { new HurtThread(gareen).start(); } } }
步骤 8 :

练习-生产者消费者问题

edit Or  姿势不对,事倍功半! 点击查看做练习的正确姿势
生产者消费者问题是一个非常典型性的线程交互的问题。

1. 使用来存放数据
1.1 把栈改造为支持线程安全
1.2 把栈的边界操作进行处理,当栈里的数据是0的时候,访问pull的线程就会等待。 当栈里的数据是200的时候,访问push的线程就会等待
2. 提供一个生产者(Producer)线程类,生产随机大写字符压入到堆栈
3. 提供一个消费者(Consumer)线程类,从堆栈中弹出字符并打印到控制台
4. 提供一个测试类,使两个生产者和三个消费者线程同时运行,结果类似如下 :
练习-生产者消费者问题
步骤 9 :

答案-生产者消费者问题

edit
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
在查看答案前,尽量先自己完成,碰到问题再来查看答案,收获会更多
查看本答案会花费5个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
查看本答案会花费5个积分,您目前总共有点积分。查看相同答案不会花费额外积分。 积分增加办法 或者一次性购买JAVA 中级总计0个答案 (总共需要0积分)
账号未激活 账号未激活,功能受限。 请点击激活
本视频是解读性视频,所以希望您已经看过了本答案的内容,带着疑问来观看,这样收获才多。 不建议一开始就观看视频

8分54秒 本视频采用html5方式播放,如无法正常播放,请将浏览器升级至最新版本,推荐火狐,chrome,360浏览器 如果装有迅雷,播放视频呈现直接下载状态,请调整 迅雷系统设置-基本设置-启动-监视全部浏览器 (去掉这个选项)


package multiplethread; import java.util.ArrayList; import java.util.LinkedList; public class MyStack<T> { LinkedList<T> values = new LinkedList<T>(); public synchronized void push(T t) { while(values.size()>=200){ try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.notifyAll(); values.addLast(t); } public synchronized T pull() { while(values.isEmpty()){ try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } this.notifyAll(); return values.removeLast(); } public T peek() { return values.getLast(); } }
package multiplethread; public class ProducerThread extends Thread{ private MyStack<Character> stack; public ProducerThread(MyStack<Character> stack,String name){ super(name); this.stack =stack; } public void run(){ while(true){ char c = randomChar(); System.out.println(this.getName()+" 压入: " + c); stack.push(c); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public char randomChar(){ return (char) (Math.random()*('Z'+1-'A') + 'A'); } }
package multiplethread; public class ConsumerThread extends Thread{ private MyStack<Character> stack; public ConsumerThread(MyStack<Character> stack,String name){ super(name); this.stack =stack; } public void run(){ while(true){ char c = stack.pull(); System.out.println(this.getName()+" 弹出: " + c); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public char randomChar(){ return (char) (Math.random()*('Z'+1-'A') + 'A'); } }
package multiplethread; public class TestThread { public static void main(String[] args) { MyStack<Character> stack = new MyStack<>(); new ProducerThread(stack, "Producer1").start(); new ProducerThread(stack, "Producer2").start(); new ConsumerThread(stack, "Consumer1").start(); new ConsumerThread(stack, "Consumer2").start(); new ConsumerThread(stack, "Consumer3").start(); } }


HOW2J公众号,关注后实时获知布最新的教程和优惠活动,谢谢。


问答区域    
2019-01-30 关于步骤7的疑问
AmberG



站长,求助。。 我在主线程中(main)用匿名类的方式创建2个线程,分别是t1(伤害线程),t2(恢复线程),然后用for循环分别遍历这2种线程,结果就是:1. 一开始会报错【Exception in thread "main" java.lang.IllegalThreadStateException】,然后才运行;2. 2种线程只运行其一(谁先遍历,就只运行谁)。Hero类是没有问题的,我是直接用站长你的源码,所以问题就在我的main中,希望获得解答。。。
package com.sunland.demo.action;

import com.sunland.demo.pojo.Hero;

/**
 * @author GX
 * Created by GX on 2019/1/28.
 */
public class MultiThreadMain {

    static class RecoverThread extends Thread{
        private Hero hero;

        public RecoverThread(Hero h) {
            this.hero = h;
        }

        @Override
        public void run() {
            while (true){
                hero.recovery();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class HurtThread extends Thread{
        private Hero hero;

        public HurtThread(Hero h) {
            this.hero = h;
        }

        @Override
        public void run() {
            while (true){
                hero.hurt();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        Hero garen = new Hero("Garen");
        garen.setHp(616);

        Thread t1 = new Thread(() -> {
           while (true)
           {
               garen.hurt();
               try {
                   Thread.sleep(100);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });

        Thread t2 = new Thread(() -> {
            while (true)
            {
                garen.recovery();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        for (int i = 0; i < 2; i ++){
//            new RecoverThread(garen).start();
            t2.start();
        }

        for (int i = 0; i < 5; i ++){
//            new HurtThread(garen).start();
            t1.start();
        }

        System.out.println("主线程结束");

    }


}
Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.start(Thread.java:708)
	at com.sunland.demo.action.MultiThreadMain.main(MultiThreadMain.java:86)
Garen 回血1点,增加血后,Garen的血量是617
Garen 回血1点,增加血后,Garen的血量是618
Garen 回血1点,增加血后,Garen的血量是619
Garen 回血1点,增加血后,Garen的血量是620
Garen 回血1点,增加血后,Garen的血量是621
Garen 回血1点,增加血后,Garen的血量是622
Garen 回血1点,增加血后,Garen的血量是623
Garen 回血1点,增加血后,Garen的血量是624
Garen 回血1点,增加血后,Garen的血量是625
Garen 回血1点,增加血后,Garen的血量是626
Garen 回血1点,增加血后,Garen的血量是627
Garen 回血1点,增加血后,Garen的血量是628
Garen 回血1点,增加血后,Garen的血量是629
Garen 回血1点,增加血后,Garen的血量是630
Garen 回血1点,增加血后,Garen的血量是631
Garen 回血1点,增加血后,Garen的血量是632
Garen 回血1点,增加血后,Garen的血量是633
Garen 回血1点,增加血后,Garen的血量是634
Garen 回血1点,增加血后,Garen的血量是635
Garen 回血1点,增加血后,Garen的血量是636
Garen 回血1点,增加血后,Garen的血量是637
Garen 回血1点,增加血后,Garen的血量是638





回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2019-01-29 关于步骤7中【用for循环实现开启多个线程】的不解
AmberG



步骤7中利用for循环开启多条线程,我觉得这个实现方式有问题。问题为:第一个开始的for循环不会结束,继而主线程不会走到第二个for循环里。因此,如果我在第一个for循环里使用hurt线程,那么英雄就会一直掉血,直到血量降至1,然后就会进入等待,但这个等待是无限的,因为主线程不会走到下一个for循环里。
package com.sunland.demo.pojo;

import java.math.BigDecimal;

public class Hero {

    private String name = "";
    private double interval = 0;
    private int hp = 1000;
    private int damage = 1;

    public Hero() {
    }

    public Hero(String name) {
        this.name = name;
    }

    public Hero(String name, double interval0, int hp, int damage) {
        this.name = name;
        this.interval = interval0;
        this.hp = hp;
        this.damage = damage;
    }

    public Hero (String name, int hp, int damage){
        this.name = name;
        this.hp = hp;
        this.damage = damage;
    }

    public synchronized void hurt(){
        if (hp <= 1) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        hp -= 1;
        System.out.format("%s 减血1点后,%s 的剩余血量为%d%n", name, name, hp);
        this.notify();

    }

    public synchronized void recovery(){
        if (hp >= 1000){
            try {
                System.out.format("血量已到达上限 %d,暂停回血%n", hp);
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        hp += 1;
        System.out.format("%s 回血1点后,%s 的血量为%d%n", name, name, hp);
        this.notify();
    }

    public void normalAttack(Hero hero){
        if (hp > 0 && !hero.isDead()) {
            hero.hp -= damage;
            System.out.format("%s 正在攻击 %s, %s 的血变成了 %d%n", name, hero.name, hero.name, hero.hp);
        }
        if (hero.isDead())
            System.out.format("%s死了", name);
    }

    public void attackHero(Hero hero){
        try {
            //1s攻击时间
//            long l = mul(this.interval, Double.valueOf(1000));
            Thread.sleep(1000);
            hero.hp -= damage;
            System.out.format("%s 正在攻击 %s, %s的血变成了 %d%n", this.name, hero.name, hero.name, hero.hp);
            if (hero.isDead()) {
                System.out.println(hero.name + "死了!");
                return;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private int totalTime = 3;

    public void adugen (Hero hero){
        int adugenDamage = this.damage * 3;
        for (int i = 0; i < totalTime; i ++){
            System.out.format("波动拳第%d波%n", i + 1);

            try {
                Thread.sleep(1000);
                hero.hp -= adugenDamage;
                System.out.format("%s 发动了第%d击波动拳,%s 的血量为 %d%n", this.name, i + 1, hero.name, hero.hp);
                if (hero.isDead()) {
                    System.out.println(hero.name + "被" + this.name + "的波动拳消灭了!");
                    break;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("开始历时5秒的充能时间...");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    public double getInterval() {
        return interval;
    }

    public void setInterval(double interval) {
        this.interval = interval;
    }

    public boolean isDead(){
        return this.hp > 0 ? false : true;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }

    public int getDamage() {
        return damage;
    }

    public void setDamage(int damage) {
        this.damage = damage;
    }

    public long mul(double d1, double d2){
        BigDecimal b1 = new BigDecimal(String.valueOf(d1));
        BigDecimal b2 = new BigDecimal(String.valueOf(d2));
        return b1.multiply(b2).longValue();

    }

}

							





回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2019-01-07 消费者生产者用string达到相似目的
2018-12-21 this.notifyAll(); values.addLast(t);顺序反了?
2018-11-28 消费者和生产者作业
2018-11-28 生产者和消费者问题作业
2018-11-23 题8生产消费线程问题
2018-10-13 生产者消费者作业
2018-09-13 多线程交互的一个问题
2018-09-07 生产者消费者问题作业
2018-09-05 关于代码重名问题
2018-08-11 关于this.notify()和this.notifyAll()的问题
2018-07-25 多线程交互
2018-07-17 写Stack类时用的Collections的synchronizeList方法,结果报illegalmonitorstateexception异常
2018-06-21 同一线程内的notify为何不会唤醒本线程内之前的wait?
2018-06-21 同一线程内的notify为何不会唤醒本线程内之前的wait?
2018-06-02 我想问一下实现Runnable接口怎么修改线程的名字呢
2018-05-30 减血的线程有更大概率原因
2018-05-16 我自己写的代码也出现了之前同学说的减到1之后一直增的情况,我发现的问题是这样的
2018-05-14 生产者消费者问题抛出空指针异常
2018-05-08 hp降为1后就不再减hp,一直都是加hp
2018-04-23 在加血线程和减血线程中都加入notify()后,用while代替if后,就用了不太好的方式,因为会大量占用CPU,拖慢性能,是不是?逻辑应该是这样
2018-04-23 生产者消费者问题
2018-04-19 debug了一下,有新的问题
2018-04-19 为啥和站长写的一样,只受伤不治疗呢
2018-04-02 交作业
2018-03-21 sleep方法为什么不能放到hurt和recover的方法里面?
2017-12-22 使用站长的代码,发现减血到1之后就一直增加了。
2017-12-14 步骤1代码执行后,盖伦的生命值降到1之后,血量只升不降
2017-12-07 生产者消费者问题
2017-11-30 生产者消费者问题
2017-11-23 关于生产者消费者问题的线程安全的MyStack类的疑惑
2017-10-24 在ProducerThread代码中有一小点逻辑问题
2017-09-16 关于notify()和notifyAll()
2017-08-24 步骤1不好的解决方式代码,如果continue上面不设置响应时间,线程t1会退出,到最后不能加血减血同步进行,只能看到加血
2017-08-20 多线程交互的练习题问题
2017-08-19 notify 用不用的问题
2017-08-17 出现异常 但还是能运行
2017-07-04 还有一个关于逻辑运算速度的问题
2017-07-04 不明白为什么要 import java.awt.GradientPaint;
2017-06-17 用while解决,好像并没有解决
2017-05-18 站长帮忙看一下 我的代码不知道为什么 当血量降到1以后 就一直加血不再减血了-.-
2017-04-07 生产者消费者问题
2017-04-04 MyStack.java
2017-02-23 不明白为啥if换成while就没问题了




提问之前请登陆
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
关于 JAVA 中级-多线程-交互 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 984886441
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: http://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图