首页 > 其他分享 >线程间通信之wait和notify

线程间通信之wait和notify

时间:2024-04-02 16:25:58浏览次数:26  
标签:Thread list 间通信 flag 线程 notify new store

synchronized

解释:java语言的一个关键字

作用:实现同步机制,控制多线程的访问,确保同一时刻只有一个线程可以进入临界区执行同步代码。

用法:加在代码块上、加在方法上、加在一个对象,

原理:不管是那种用法,都会有一个对象(指定的对象、class的实例对象、class对象),这个对象又会一一对应一个监视器对象,然后对监视器对象加锁,编译成字节码后,会有monitorenter和monitorexit标记同步代码块的入口和出口

监视器对象(ObjectMonitor)里有一些变量,记录一些信息

ObjectMonitor() {
    _header       = NULL;
    _count        = 0;   // 重入次数
    _waiters      = 0,   // 等待线程数
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;  // 当前持有锁的线程
    _WaitSet      = NULL;  // 调用了 wait 方法的线程被阻塞 放置在这里
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ; // 等待锁 处于block的线程 有资格成为候选资源的线程
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
}

 

wait

解释:是Object类的一个final方法,会抛出InterruptedException

作用:让当前线程进入等待状态,并释放持有的锁

原理:会将当前线程加入ObjectMonitor的_WaitSet,当前线程随即释放锁,并等待在原地,停止执行后续代码

用法:使用synchronized包裹,抛出或者处理中断异常

    public void doWait() throws InterruptedException {
        synchronized (obj) {
            obj.wait();
        }
    }

 

 

notify

解释:是Object类的一个final native方法

作用:随机唤醒一个线程,这个线程是waiting在当前object的monitor,即加入ObjectMonitor的_WaitSet的线程

原理:从ObjectMonitor的_WaitSet中随机取出一个线程唤醒,这个线程随即获取锁,继续执行后续的代码

用法:使用synchronized包裹

    public void doNotify() {
        synchronized (obj) {
            obj.notify();
        }
    }

 

notifyAll

同notify,只不过唤醒所有的等待线程,所有的等待线程随即竞争同步锁

 

下面是一个经典的生产者消费者模型,由于是多个生产者多个消费者,在此,在仓库满了以后,我们使用wait让生产者进入等待,在仓库空了以后让消费者进入等待。当生产者将商品放入仓库以后,通知等待的消费者继续消费 或者 当消费者消费了商品以后,通知等待的生产者继续生产,此处由于是多个生产者和多个消费者,如果使用nofity,可能唤醒的不是想要唤醒的线程。 但是使用notifyAll,需要做一个保护,下面代码中的while。  在仓库满了以后,如果唤醒的生产者竞争到了锁,还是会将商品放入了仓库,导致仓库爆了,或者  在仓库空了以后,如果唤醒的消费者竞争到了锁,会消费不到商品。

public class Test {
    public static void main(String[] args) {
        new Test().start();
    }
    private void start(){
        Store store = new Store(10);
        Thread producer1 = new Thread(new Producer("producer1",store, 1000));
        Thread producer2 = new Thread(new Producer("producer2",store, 1000));
        Thread consumer1 = new Thread(new Consumer("consumer1",store, 1000));
        Thread consumer2 = new Thread(new Consumer("consumer2",store, 1000));
        Thread consumer3 = new Thread(new Consumer("consumer3",store, 1000));
        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        consumer3.start();
    }

    class Store {
        final int capacity;
        final List<String> list;
        public Store(int capacity){
            this.capacity = capacity;
            list = new ArrayList<>(capacity);
        }
        public String take() throws InterruptedException {
            synchronized (list) {
                while (list.isEmpty()) { // prevent consumer notify consumer, so use while
                    list.wait();
                }
                String product = list.remove(list.size() - 1);
                list.notifyAll();
                return product;
            }
        }
        public void add(String product) throws InterruptedException {
            synchronized (list) {
                while (list.size() >= capacity) { // prevent producer notify producer, so use while
                    list.wait();
                }
                list.add(product);
                list.notifyAll();
            }
        }
    }
    class Producer implements Runnable{
        String flag;
        Store store;
        int interval;
        public Producer(String flag, Store store, int interval) {
            this.flag = flag;
            this.store = store;
            this.interval = interval;
        }
        @Override
        public void run() {
            for(long i=0;;i++) {
                try {
                    Thread.sleep(interval);
                } catch (InterruptedException e) {
                    System.out.println("sleep InterruptedException so finish thread "+flag);
                    break;
                }
                String product = "product-"+flag+"-"+i;
                System.out.println(flag+" produce "+product);
                try {
                    store.add(product);
                } catch (InterruptedException e) {
                    System.out.println("wait/notify InterruptedException so finish thread "+flag);
                    break;
                }
            }
        }
    }
    class Consumer implements Runnable{
        String flag;
        Store store;
        int interval;
        public Consumer(String flag, Store store, int interval) {
            this.flag = flag;
            this.store = store;
            this.interval = interval;
        }
        @Override
        public void run() {
            for(;;) {
                try {
                    Thread.sleep(interval);
                } catch (InterruptedException e) {
                    System.out.println("sleep InterruptedException so finish thread "+flag);
                    break;
                }
                try {
                    String product = store.take();
                    System.out.println(flag+" consume "+product);
                } catch (InterruptedException e) {
                    System.out.println("wait/notify InterruptedException so finish thread "+flag);
                    break;
                }
            }
        }
    }
}

  

 

标签:Thread,list,间通信,flag,线程,notify,new,store
From: https://www.cnblogs.com/huainanyin/p/18110827

相关文章

  • 多线程的案例
    目录1.单例模式1.1饿汉模式1.2懒汉模式-单线程版1.3懒汉模式-多线程版1.3懒汉模式-多线程版(改进)2.阻塞队列2.1阻塞队列是什么2.2生产者消费模型2.3标准库中的阻塞队列2.4阻塞队列实现3.定时器3.1定时器是什么3.2标准库中的定时器3.3实现定时器4.线程池4.1线......
  • How to fix: “inotify cannot be used, reverting to polling: Too many open files
    Youareherebecauseyouhadencounteredtheerrorinthetitle.InthisarticleIwillexplaintheerrorandstepsnecessarytoreproduceandfixit.Themostrelevantdocumentationforinotifyisthe inotifymanpage, thatyoucanalsoreadlocallywith......
  • Worker 进行多线程任务开发
    概念介绍在OpenHarmony中,UI线程负责处理UI事件和用户交互,而Worker线程用于处理耗时操作,以提高应用程序的响应速度和用户体验。Worker线程是与主线程并行的独立线程,通常用于执行后台任务。需要注意的是,Worker线程中不能直接修改UI元素,UI更新必须在UI线程中进......
  • 使用jstack查看当前进程全部线程的状态
     1.使用jps命令找到进程的PID$jps225648Jps5268127284Launcher226980Launcher227624ConcurrencyTest2.使用jstack命令dump出线程信息jstack227624>./thread.dump 3.分析线程的状态信息$grepjava.lang.Thread.Statethread.dump|awk'{print$2$3$4$5}'|uniq......
  • 多线程编程相关理论
    Happens-Before原则:如果操作AHappens-Before操作B,那么操作A的结果对操作B是可见的,并且操作A在操作B之前执行。这确保了当一个线程修改了某个变量的值,其他线程能够看到这个修改后的值,从而避免了数据不一致的问题。Happens-Before的关键规则:程序次序规则:在一个线程内,按照控制流顺......
  • CSci 4061多线程图像匹配服务器
    CSci4061:操作系统简介,2024年春季项目#3:多线程图像匹配服务器中间提交截止时间:2023年4月4日下午11:59(CDT)最终提交截止时间:下午11:59(CDT),4。12,20231.背景这个实验室的目的是使用C语言中的POSIX线程(pthreads)来学习线程编程和同步方法。在这个项目中,我们将使用多线程来提高服务器的......
  • C#中的多线程编程
    多线程编程在C#和WPF日常开发中非常常见,特别是在需要处理并发任务或者提高程序性能的场景下。以下是关于多线程编程的知识点,以及可能会在面试中被问到的一些问题和答案:多线程编程的知识点:线程和进程:线程是程序执行流的最小单元,多个线程可以共享同一个进程的资源。在C#......
  • 如何根据服务器配置选择默认的线程数量:实战指南
    在现代软件开发与部署中,合理设置线程数量对于充分发挥服务器性能、提升应用程序响应速度和资源利用率至关重要。本文将深入探讨如何根据服务器配置来选择默认的线程数量,旨在为开发者提供一套科学、实用的决策框架。我们将讨论关键因素、评估方法和最佳实践,帮助您在复杂的工......
  • 线程池 核心原理
    文章目录线程池核心原理ThreadPoolExecutor主要构造函数:执行任务:关闭线程池:线程池生命周期:Executor框架线程池实战步骤1:创建线程池步骤2:创建任务步骤3:提交任务到线程池步骤4:关闭线程池完整示例线程池核心原理线程池的核心原理是基于“池化”(Pooling)思想,这种思想在......
  • 线程池
    文章目录线程池线程池的优点线程池的组成使用线程池的场景线程池配置什么情况下建议不要使用线程池线程池线程池(ThreadPool)是一种在多线程环境下常用的一种资源管理手段,主要用于优化线程的创建和管理,以提高程序性能和资源利用率。线程池维护一个已经创建的线程的集......