首页 > 其他分享 >在多线程里面,为什么推荐使用notifyAll而不是notify

在多线程里面,为什么推荐使用notifyAll而不是notify

时间:2023-10-30 16:12:00浏览次数:28  
标签:P2 product notifyAll void notify new 多线程 public

在多线程里面,为什么推荐使用notifyAll而不是notify?


结论:notify容易造成死锁

1、无论使用notify或者notifyAll,都是随机唤醒线程

2、notify是随机唤醒一个线程去执行,noifyAll是唤醒所有线程,然后去抢占锁,去执行

怎么产生死锁现象:

P – 生产者 调用 putproduct C – 消费者 调用 consumer。

  1. P2 调用product,发现满了,在wait里面等了。

  2. P2 调用product,发现满了,在wait里面等了。

  3. P2 调用product,发现满了,在wait里面等了。

  4. C1 想来拿,C2,C3 就在 consumer里面等着。

  5. C1 开始执行,移除remove,然后调用 notify 然后退出。

  • 如果 C1 把 C2 唤醒了,所以P2 (其他的都得等)只能在product方法上等着。
  • C2 检查 while 循环发现此时队列是空的,所以就在 wait 里面等着。
  • C3 也比 P2 先执行,那么发现也是空的,只能等着了。
  1. 这时候我们发现 P2、C2、C3 都在等着锁,最终 P2 拿到了锁,放一个 1,notify,然后退出。

  2. P2 这个时候唤醒了P3,P3发现队列是满的,没办法,只能等它变为空。 8. 这时候没有别的调用了,那么现在这三个线程(P3, C2,C3)就全部变成 suspend 了,也就是死锁了。

代码示例
public class Thread03{

    private Buffer mbuffer = new Buffer();
    // private List<Object> list = new ArrayList<>();

    public void product(){
        synchronized (this) {
            while (mbuffer.isFull()){
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            mbuffer.add();
            notify();
        }

    }

    public void consumer(){
        synchronized (this) {
            while (mbuffer.isEmpty()){
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            mbuffer.remove();
            notify();
        }

    }

    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) {
        Thread03 thread03 = new Thread03();
        Runnable product = new Runnable() {
            int count = 4;

            @Override
            public void run() {
                while (count-- > 0) {
                    thread03.product();
                }

            }
        };

        Runnable consumer = new Runnable(){
            @Override
            public void run() {
                int count = 4;
                while (count-- >0){
                    thread03.consumer();
                }            }
        };

        for (int i = 0; i < 2; i++) {
            new Thread(product).start();
        }

        for (int i = 0; i < 2; i++) {
            new Thread(consumer).start();
        }
    }

}

标签:P2,product,notifyAll,void,notify,new,多线程,public
From: https://www.cnblogs.com/snowflow/p/17798120.html

相关文章

  • Tornado实现多线程/多进程的HTTP服务
    用tornadoweb服务的基本流程原文链接1.实现处理请求的Handler,该类继承自tornado.web.RequestHandler,实现用于请求的对应方法如:get,post等。返回内容用self.write方法输出。**2.实例化一个Application。**构造函数的参数是一个Handler列表,通过正则表达式,将请求与Handler对应起来......
  • 多线程读取多个摄像头并把画面显示到Tkinter 的 label上面
    importcv2importthreadingimporttkinterastkfromPILimportImage,ImageTkclassCameraThread(threading.Thread):def__init__(self,camera_index,label):threading.Thread.__init__(self)self.camera_index=camera_indexs......
  • C++多线程编程——线程的基本概念和使用方法
    什么是线程?在计算机科学中,线程是进程中的一个执行控制单元,也被称为执行路径。每个进程可以包含多个线程,每条线程并行执行不同的任务。线程是操作系统可识别的最小执行和调度单位。进程和线程的区别进程是程序在某个数据集合上的一次运行活动,也是操作系统进行资源分配和保护的......
  • java实现多线程下载器
    前言:......
  • [Java]Java初学之多线程05--Lock锁
    Intro除了synchronized关键字,从JDK5.0开始,Java提供了更强大的线程同步机制--通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。本文简单讲一下Lock锁的概念以及简单应用。正文其实理解了synchronized关键字后,Lock锁的理解就会变得简单起来。Lock锁实际上是使用了j......
  • 手把手教你:如何用Java多线程模拟银行叫号服务
    大家好,我是小米!今天,我将和大家一起探讨一个非常有趣的话题——Java多线程模拟银行叫号服务。这不仅是一个有趣的编程练习,还可以帮助我们更好地理解多线程编程和并发控制。在这篇文章中,我将带领大家一步步实现一个模拟银行叫号服务系统,包括三个窗口、按叫号顺序依次到窗口服务、每个......
  • [Java]Java初学之多线程03--同步与锁
    Intro本篇文章主要关于多线程"同步"以及"锁"的相关内容~正文同步(Synchronize)概念“同步”是基于“并发”的需求而出现的所谓并发,就是同一个对象被多个线程同时操作,比如两个人同时从同一个账户取钱,再比如春运抢票。多个线程同时使用一个资源,必然会造成混乱。想象一下从前......
  • rust 创建多线程web server
    创建一个httpserver,处理http请求。创建一个单线程的web服务webserver中主要的两个协议是http和tcp。tcp是底层协议,http是构建在tcp之上的。通过std::net库创建一个tcp连接的监听对象,监听地址为127.0.0.1:8080.usestd::net::TcpListener;fnmain(){l......
  • 前端多线程处理——async/await
    async从字面上看就是“异步”,它放在函数定义之前,是使该函数在调用时开一个子线程,以不影响主线程的运行。而await经常和async组合使用,在async定义的函数中来等待需要时间运行的代码(如ajax请求、Promise对象)的运行结果,以做后续的处理。  如下面的返回Promise对象......
  • Java基础 多线程的 6 种状态
       Java的虚拟机当中没有定义运行状态,因为当线程抢夺到CPU执行权的时候,虚拟机会把当前线程交给操作系统管理,虚拟机就不管了。 ......