多线程中wait()、sleep()、notify()和notifyAll()方法异同点【面试】

现在面试基本上都会被问及到多线程,就有很高概率问到wait()sleep() 这两者的区别

1、wait()、sleep() 方法相同点

(1)都是对线程的操作;

(2)都需要抛异常; (这一点我遇到很多人答错,记住这两者都会抛异常)

(3)都会让当前运行线程进入阻塞状态

(4)都能在阻塞过程中感受到中断信号

2、wait()、sleep() 方法不同点

(1)使用位置不同: wait() 方法必须在synchronized 同步代码中,sleep() 则不需要;

(2)申明位置不同: wait() 方法是 Object类 中的方法,sleep() 方法是 Thread类中的静态方法

(3)调用时是否释放锁不同:wait() 调用时线程是要释放同步监视器(锁)的,sleep() 不会释放同步监视器(锁);

(4)wait() 方法要结合 notify() 方法或者 notifyAll() 方法一起使用,不然就会一直阻塞线程。(没有设置时间的情况下)

(5)sleep() 方法是必须要求指定一个时间,超时之后就会恢复操作,而 wait() 方法如果没有设置时间的话,会一直处于等待状态,只有等到被唤醒或者被中断才会恢复。

重点说明一下:

1、wait() 是和 synchronized 锁一起使用,而 await() 是和 Lock 锁一起使用,await() 方法是 Condition 接口中的方法;

2、wait() 为什么必须在 synchronized 同步代码中使用呢 ?

主要原因是为了程序的安全性,必须保证每一个线程持有锁之后的操作都是原子的,不然可能会带来线程之间的通信失败。比如说本来现在是应该阻塞当前线程,由于不是原子的,这时候要是没有阻塞这个线程,那么此时要是执行到要去唤醒刚刚没有被阻塞的那个线程就是不对的。

另外 wait() 方法是会释放锁的,要是不是原子的,第一个线程还没有执行到 wait() 方法,也就是还没有释放当前锁,此时另外一个线程就开始执行显然是不会持有锁的,那么会报IllegalMonitorStateException异常的。

3、为什么会把 wait() 方法定义在 Object类中,sleep() 方法定义在 Thread类中 ?(我的理解是:)

我们都知道,Object 类是所有对象的父类,另外加锁加锁其实就是给对象进行加锁,那么 wait()、notify()、notifyAll()定义在 Object 这个对象父类中就是理所当然的了,而不是 Thread 线程类中;
如果把wait() 、notify()、notifyAll() 方法定义在 Thread 类中,我们就不好让一个线程持有对象锁(非同一时刻),又不好确定线程等待的是哪一把锁?既然是线程等待某一个对象的锁,那么操作对象是最为合适的,而不是线程;
另外:每一个对象的对象头 markword 里都会有锁状态信息,也就是用此来表示对象的锁状态,是无锁、偏向锁、轻量级锁、重量级锁呢?而不是在每一个线程里。想了解对象的对象头 markword 或者 synchronized 的锁膨胀机制,可以看这里。

3、notify() 方法和 notifyAll() 方法

(1)notify() 方法和 notifyAll() 方法是Object类中定义的方法;

(2)notify() 方法:

①线程不能一直在等待集合中,必须有方法对其进行唤醒,notify() 方法可以对线程进行唤醒;
②使用 this 作为当前对象的引用,故可以直接写成 notify() 进行调用,而不必用当前对象点上 notify() 方法;(这一点下面Demo中
有演示)
③当使用某个对象的 notify() 方法时,将从该对象的等待集合中任意选择一个等待的线程唤醒,唤醒的线程将从等待集合中删除

(3)notifyAll()方法:

①notifyAll() 方法会将所有在等待集合中的线程唤醒
②由于所有的被唤醒的线程仍然要去争用synchronized锁,而synchronized锁具有排他性,最终只有一个线程获得该锁,进行执行状态,其他线程仍要继续等待,只是现在被唤醒的这些线程都有去抢夺同步监视器(锁)的权利了。

4、wait() 方法 sleep() 方法使用及抛异常

wait() 方法演示:

public synchronized void productProduct() {
if (productCount < 20) {//店员有20个产品就停止生产产品
productCount++;
notify();//唤醒阻塞的一个线程
System.out.println(Thread.currentThread().getName() + "生产了第" + productCount + "个产品");
} else {//要是有20个产品就等待消费者消费到20个以下

try {
wait();//线程执行此句就会进入阻塞状态,注意的是:wait()必须在同步方法或者同步代码块中
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

sleep() 方法演示:

    @Override
public void run() {
System.out.println(getName() + ":开始生产产品");
while (true) {

//让当前线程休眠10毫秒
try {
Thread.sleep(10); //任意位置使用sleep方法都是可以的,
} catch (InterruptedException e) {
e.printStackTrace();
}
clerk.productProduct();
}

写了一个小的Demo,方便初学者对多线程的理解,希望有用

5、最简单的生产者和消费者问题

package TreadTest;
/*
生产者不断的生产产品给店员,消费者在店员这里消费产品,要求是当店员处有最多只能存放20个产品,
*/
class Clerk {//中间者(店员)
private int productCount = 0;

//生产者生产产品方法
public synchronized void productProduct() {
if (productCount < 20) {//店员有20个产品就停止生产产品
productCount++;
notify();//唤醒
System.out.println(Thread.currentThread().getName() + "生产了第" + productCount + "个产品");
} else {//要是有20个产品就等待消费者消费到20个以下
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//消费者消费产品
public synchronized void customerProduct() {
if (productCount > 0) {
System.out.println(Thread.currentThread().getName() + "消费了第" + productCount + "个产品");
productCount--;
notify();
} else {

try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

//生产者
class Product extends Thread {
private Clerk clerk;

public Product(Clerk clerk) {
this.clerk = clerk;
}

@Override
public void run() {
System.out.println(getName() + ":开始生产产品");
while (true) {

try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}

clerk.productProduct();
}
}
}

//消费者
class Customer extends Thread {
private Clerk clerk;

public Customer(Clerk clerk) {
this.clerk = clerk;
}

@Override
public void run() {
System.out.println(getName() + ":开始消费产品");
while (true) {

try {
Thread.sleep(50);
} catch (Exception e) {
e.printStackTrace();
}

clerk.customerProduct();
}

}
}

public class ProductTest {
public static void main(String[] args) {
Clerk clerk = new Clerk();//生产者和消费者去共同对商品进行操作,保证生产者和消费者是操作的同一个店员(共享数据)

Product p1 = new Product(clerk);//一个生产者
Customer c1 = new Customer(clerk);//两个消费者
Customer c2 = new Customer(clerk);

p1.setName("生产者1");
c1.setName("消费者1");
c2.setName("消费者2");

p1.start();
c1.start();
c2.start();
}
}

另外:要注意 notify() 的虚假唤醒,把 if 换为 while 即可解决。

由于while条件是true,所有程序会一直运行下去,结果:

消费者1:开始消费产品
生产者1:开始生产产品
消费者2:开始消费产品
生产者1生产了第1个产品
生产者1生产了第2个产品
消费者1消费了第2个产品
消费者2消费了第1个产品
生产者1生产了第1个产品
生产者1生产了第2个产品
生产者1生产了第3个产品
消费者1消费了第3个产品
消费者2消费了第2个产品
生产者1生产了第2个产品
生产者1生产了第3个产品
生产者1生产了第4个产品
消费者1消费了第4个产品
消费者2消费了第3个产品
生产者1生产了第3个产品
生产者1生产了第4个产品
生产者1生产了第5个产品
消费者1消费了第5个产品
消费者2消费了第4个产品
生产者1生产了第4个产品
生产者1生产了第5个产品
生产者1生产了第6个产品
...

有用点个关注,手留余香!? ? ?

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

多线程中wait()、sleep()、notify()和notifyAll()方法异同点【面试】

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » 多线程中wait()、sleep()、notify()和notifyAll()方法异同点【面试】
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏