课程相关疑问

课程相关疑问

package com.imooc.test3;

/**
 * @author LZ
 * @date 2019/11/25 18:10:12
 * @description
 */
public class Test {
    public static void main(String[] args) {
        Goods g = new Goods();
        X1 x1 = new X1(g);
        X2 x2 = new X2(g);
        Thread t1 = new Thread(x1);
        Thread t2 = new Thread(x2);
        t1.start();
        t2.start();
    }
}
package com.imooc.test3;

/**
 * @author LZ
 * @date 2019/11/25 18:22:22
 * @description
 */
public class Goods {
    private int money;
    boolean flag = false;
    public Goods(){}
    public Goods(int money){
        setMoney(money);
    }
    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
    public void save(){
        synchronized (this) {
            if (!flag) {
                setMoney(getMoney() + 100);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "增加100后的钱为:" + getMoney());
                flag = true;
                notifyAll();
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public void draw(){
        synchronized (this) {
            if (flag) {
                setMoney(getMoney() - 100);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "减少100后的钱为:" + getMoney());
                flag = false;
                notifyAll();
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
package com.imooc.test3;

/**
 * @author LZ
 * @date 2019/11/25 18:10:32
 * @description
 */
public class X1 implements Runnable{
    Goods goods;
    public X1(){}
    public X1(Goods goods){
        this.goods = goods;
    }
    @Override
    public void run() {
        int i=3;
        while (i>0) {
            goods.save();
            i--;
        }
    }
}
package com.imooc.test3;

/**
 * @author LZ
 * @date 2019/11/25 18:10:38
 * @description
 */
public class X2 implements Runnable{
    Goods goods;
    public X2(){}
    public X2(Goods goods){
        this.goods = goods;
    }
    @Override
    public void run() {
        int i=3;
        while (i>0) {
            goods.draw();
            i--;
        }
    }
}

疑问1.在没有加入wait();和notifyAll();方法时,我打印输出时都是先输出两三个线程1的信息,然后再输出一两个线程2的信息依次循环知道结束,并没有像课程中老师所输出的那样大部分都是线程1,2交替打印信息。我也觉得我输出的很奇怪,因为我代码中也调用了sleep()方法,当线程1休眠时正常来说线程2会马上夺得cup的资源进行输出打印

疑问2.在视频的18:23的时候,老师先调用了wait();方法然后再notifyAll();这里不懂执行顺序,当执行wait()时线程不是进入等待(阻塞)了么,下面的代码(输出语句等待)还会执行么?既然已经阻塞了,它下面调用了notifyAll();方法会不会把刚刚调用了wait()方法的线程也给唤醒了啊,那不就是唤醒了当前线程和另外一共两个线程了

疑问3.同步锁和wait()sleep()notifyAll()等操作线程的方法,在线程类中调用和在被操作的类里面方法调用有什么区别?

正在回答

登陆购买课程后可参与讨论,去登陆

2回答

同学你好,

1、对于同学的第一个疑问。同学所描述的先输出两三个线程1的信息,然后再输出一两个线程2的信息依次循环直到结束,这里是因为在没有添加wait();和notifyAll();时,线程的执行过程是随机的,因为调用sleep()方法,使当前线程进入休眠,大大提高了线程2的获取cpu的概率,这里同学没有实现与老师类似的效果,一是由于线程的执行过程是随机的,二是建议同学将sleep休眠的方法编写在X1和X2类中,这样才能保证,每执行完一次线程1的方法,进入休眠,线程2才可以获取到cpu。

如:

http://img1.sycdn.imooc.com//climg/5ddcf8330976606205840505.jpg

2、在视频的18:23的时候,老师先调用了wait();方法然后再notifyAll();这里不懂执行顺序,当执行wait()时线程不是进入等待(阻塞)了么,下面的代码(输出语句等待)还会执行么?既然已经阻塞了,它下面调用了notifyAll();方法会不会把刚刚调用了wait()方法的线程也给唤醒了啊,那不就是唤醒了当前线程和另外一共两个线程了

整个的执行顺序是:

首先同学要明白,这里定义flag的目的是为了保证生成数据一个就读取数据一个的效果,初始值为false,

在第一次执行时,当前没有数据生成,所以我们需要调用set()方法去生产数据,也就是执行如下内容,进行输出生产数据的内容,如:

http://img1.sycdn.imooc.com//climg/5ddcf96309667e2905560364.jpg

这时,数据生产完毕,有数据了,就需要进行读取数据了,也就是将flag设为true时表示有数据了,可以消费了。所以将flag设置为true。调用notifyAll(),将所有线程唤醒,然后回到Producer类的方法调用处,进行睡眠1s,如:

http://img1.sycdn.imooc.com//climg/5ddcf9ec090b2e4e05980474.jpg

然后执行下一次的循环,这时执行set()方法,flag为true,则执行wait()方法,将当前线程进入等待。

这时执行消费数据的线程,也就是get()方法,flag为true,不执行语句体,也就是wait()方法,进行获取数据,进行输出,再将flag设为false,表示已经读取完毕。没有数据了。需要再次进行生成数据,最后唤醒线程,将当前线程设为等待。如:

http://img1.sycdn.imooc.com//climg/5ddcfa5509ecee8405290337.jpg

3、同步锁和wait()sleep()notifyAll()等操作线程的方法,在线程类中调用和在被操作的类里面方法调用有什么区别?

synchronized同步锁表示同一时间只能有一个线程进入方法中执行。防止多个线程进入方法进行执行代码,造成数据不一致。

wait()和notifyAll():wait()表示用来使得当前线程进入等待状态,notifyAll()方法:该方法用来唤醒处于等待状态的所有线程。

sleep():表示使当前线程进入休眠。

如果我的回答解决了你的疑惑,请采纳!祝:学习愉快!

  • qq_粽翎_0 提问者 #1
    理解了,非常感谢耐心解答! 还有一点点小问题 wait sleep方法写在什么地方就是默认为本线程调用的是吗? 还有就是sleep方法后要等时间结束才能自动回到可运行状态吗?有没有打断睡眠的方法 wait方法是一定要notify(all)才能回到可运行状态是么?不然就一直阻塞下去?
    2019-11-26 18:45:59
  • 好帮手慕酷酷 回复 提问者 qq_粽翎_0 #2
    同学你好,1、wait sleep方法写在什么地方就是默认为本线程调用的是吗?是的 2、还有就是sleep方法后要等时间结束才能自动回到可运行状态吗? 这里因为线程的执行过程是随机的,也许睡眠之后,该线程也没有转为可运行状态,也是有可能的。3、有没有打断睡眠的方法?没有哦~ 4、wait方法是一定要notifyAll才能回到可运行状态是么?不然就一直阻塞下去?你的理解是正确的。如果我的回答解决了你的疑惑,请采纳!祝:学习愉快!
    2019-11-26 19:11:35
  • qq_粽翎_0 提问者 回复 好帮手慕酷酷 #3
    可以举一下例子吗,就是sleep之后为啥不能回到可运行状态呢?还有个问题哈,就是开启线程不是用start方法嘛,如果我用封装了Runnable实现类的thread对象,不是调用start方法启动线程,而是调用它所重写的run方法,是不是不会开启一个新线程,程序运行的还是只有main方法的一个线程
    2019-11-26 19:36:13
好帮手慕小班 2019-11-26 14:26:55

同学你好,1、同学所说的输出时都是先输出两三个线程1的信息,然后再输出一两个线程2的信息依次循环,老师测试修改代码并没有复现同学所说的现象。比如

http://img1.sycdn.imooc.com//climg/5ddcc11809508b5f02280159.jpg

        这里同学需要知道一个小知识点:sleep()方法没有释放锁,而wait()方法释放了锁,使得其他线程此时可以使用同步代码块(同步方法)。

        2、wait();方法与notifyAll();方法的执行

       这里线程并不是直接被唤醒的,因为在前面的执行过程中 第一次flag等于false时,表示没有数据产生,数据为空,此时线程不进入等待,所以执行下面生产数据的代码,进入生产数据,生产完毕,容器中已经有数据, flag设置为true,线程执行进行消费,只有flag判断为ture时,进行消费,这个过程是交换执行,这个是随机的。

        两个的线程在执行过程可能会出现,当前线程自己调用了wait()方法进行等待了,会在中途执行另一个线程,这时当前线程为false,而另一个线程可能flag还没执行到为true时,但是同一时间都想要争夺CPU资源来进行生产和消费,就造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。所以要添加notifyAll()进行唤醒线程~

        3、wait方法是执行线程等待的方法,synchronized修饰的代码块,就是一段代码被锁起来,不能同步执行这段代码,只能一个一个来执行。notifyAll ()是会通知所有阻塞中的线程重新开始运行。

         wait()一般与sychronized关键字搭配使用,因为在JAVA中进程同步是通过synchronized()来实现的,在实现同步机制时,wait()与notify(需要与synchronized()一起使用,实现同步的效果!

如果我的回答解决了你的疑惑,请采纳。祝:学习愉快~

  • 提问者 qq_粽翎_0 #1
    你都不能根据我的问题来具体回答,都是回答个大概。找慕酷酷来帮我回答下可以不,谢谢
    2019-11-26 14:41:28
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师