当前位置: 代码迷 >> 综合 >> 多线程之wait(),sleep(),notify(),notifyAll()
  详细解决方案

多线程之wait(),sleep(),notify(),notifyAll()

热度:53   发布时间:2023-10-17 03:04:50.0

本文主要理解锁与这些方法的关系(参考了其他文章)

1.wait()和sleep()的区别

   1.1 wait()

  1. wait()使当前线程阻塞,前提是必须先获得锁,一般配合synchronized 关键字使用,即一般在synchronized 同步代码块里使用 wait()、notify/notifyAll() 方法。
  2. wait()方法则是指当前线程让自己暂时退让出同步资源锁,以便其他正在等待该资源的线程得到该资源进而运行,只有调用了notify()方法,之前调用wait()的线程才会解除wait状态,可以去参与竞争同步资源锁,进而得到执行。(注意:notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度)

 

   1.2 sleep() 

sleep()方法正在执行的线程主动让出CPU,在sleep指定时间后CPU再回到该线程继续往下执行(注意:sleep方法只让出了CPU,而并不会释放同步资源锁!!!)

 

2. notify()和notifyAll()的区别

   notify()是唤醒一个线程,notifyAll()是唤醒全部线程,但是唤醒然后呢,不管是notify()还是notifyAll(),最终拿到锁的只会有一个线程,

 3. notify()和notifyAll()和死锁的关系

  之前我们先了解下锁的释放

         当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源。

 

参考 https://www.jianshu.com/p/25e243850bd2?appinstall=0 的demo

package com.learn.LinkedT;import java.util.List;
import java.util.ArrayList;/*** 多线程之wait(),notify(),notifyall()*/
public class Something {private Buffer mBuf = new Buffer();public void produce() {synchronized (this) {while (mBuf.isFull()) {try {System.out.println(Thread.currentThread().toString()+"--------produce");wait();} catch (InterruptedException e) {e.printStackTrace();}}mBuf.add();//            notifyAll();notify();}}public void consume() {synchronized (this) {while (mBuf.isEmpty()) {try {System.out.println(Thread.currentThread().toString()+"--------consume");wait();} catch (InterruptedException e) {e.printStackTrace();}}mBuf.remove();notify();
//            notifyAll();}}private class Buffer {private static final int MAX_CAPACITY = 1;private List innerList = new ArrayList(MAX_CAPACITY);void add() {if (isFull()) {throw new IndexOutOfBoundsException();} else {innerList.add(new Object());}System.out.println(Thread.currentThread().toString() + " add");}void remove() {if (isEmpty()) {throw new IndexOutOfBoundsException();} else {innerList.remove(MAX_CAPACITY - 1);}System.out.println(Thread.currentThread().toString() + " remove");}boolean isEmpty() {return innerList.isEmpty();}boolean isFull() {return innerList.size() == MAX_CAPACITY;}}public static void main(String[] args) {final Something sth = new Something();Runnable runProduce = new Runnable(){int count = 4;public void run() {while (count-- >0){sth.produce();}}};Runnable runConsume = new Runnable() {int count = 4;public void run() {while (count-- > 0) {sth.consume();}}};for (int i = 0; i < 2; i++) {
//            System.out.println("for--first---"+i);new Thread(runConsume).start();}for (int i = 0; i < 2; i++) {
//            System.out.println("for-second---"+i);new Thread(runProduce).start();}}
}

多线程之wait(),sleep(),notify(),notifyAll() 

使用notify出现死锁,分析下产生死锁的原因

生产者和消费者都是2个线程

线程0,1,2,3对应消费者1,消费者2,生产者1,生产者2

  1. 消费者1拿到锁----->buffer为空,wait()释放锁,现象1
  2. 生产者2拿到锁----->buffer为空,add,现象2,notify()
  3. 生产者2进入循环-->buffer满,wait(),释放锁,现象3注意是同一个线程
  4. 生产者1拿到锁----->buffer满,wait(),现象4
  5. 消费者2拿到步骤一释放的锁----->buffer满,remove,现象5,notify()
  6. 消费者2进入循环---->buffer为空,wait(),释放锁,现象6
  7. 生产者2唤醒---->buffer为空,生产,现象7,并进入循环,buffer满,现象8,wait()释放锁
  8. 生产者1拿到锁---->buffer满,现象9,wait(),释放锁
  9. 前面有两个notify,还有一个此时唤醒消费者1---->buffer满,remove,现象10,notify(),并进入循环,buffer空,wait(),现象11
  10. 消费者2被唤醒---->buffer为空,wait()

此时生产者和消费者都wait了!死锁形成,如果用notifyAll()就不会出现这种情况,因为wait的线程总会被唤醒,然后拿到锁

 

  相关解决方案