zoukankan      html  css  js  c++  java
  • 线程等待唤醒

    什么是等待唤醒机制

    这是多个线程间的一种协作机制。谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。就好比在公司里你和你的同事们,你们可能存在在晋升时的竞争,但更多时候你们更多是一起合作以完成某些任务。

    就是在一个线程进行了规定操作后,就进入等待状态(wait()), 等待其他线程执行完他们的指定代码过后 再将其唤醒(notify());在有多个线程进行等待时, 如果需要,可以使用 notifyAll()来唤醒所有的等待线程。

    wait/notify 就是线程间的一种协作机制。

    等待唤醒中的方法

    等待唤醒机制就是用于解决线程间通信的问题的,使用到的3个方法的含义如下:

    1. wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态即是 WAITING。它还要等着别的线程执行一个特别的动作,也即是“通知(notify)”在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中

    2. notify:则选取所通知对象的 wait set 中的一个线程释放;例如,餐馆有空位置后,等候就餐最久的顾客最先入座。

    3. notifyAll:则释放所通知对象的 wait set 上的全部线程。

    注意:

    哪怕只通知了一个等待的线程,被通知线程也不能立即恢复执行,因为它当初中断的地方是在同步块内,而此刻它已经不持有锁,所以她需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait 方法之后的地方恢复执行。

    总结如下:

    • 如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE 状态;

    • 否则,从 wait set 出来,又进入 entry set,线程就从 WAITING 状态又变成 BLOCKED 状态

    调用wait和notify方法需要注意的细节

    1. wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。

    2. wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。

    3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。

    例子

    package com.thread;
    
    
    public class BaoZi  {
    
        public String xianer;
    
        public String pier;
    
        boolean  flag = false ;//包子资源 是否存在  包子资源状态
    
        public static void main(String[] args) {
            BaoZi baoZi = new BaoZi();
            BaoZiPu baoZiPu = new BaoZiPu("包子铺",baoZi);
            ChiHuo chiHuo = new ChiHuo("吃货",baoZi);
    
            baoZiPu.start();
    
            chiHuo.start();
    
    
    
        }
    }
    package com.thread;
    
    
    public class ChiHuo  extends Thread{
    
        private BaoZi baozi;
    
        public ChiHuo(String name, BaoZi baozi) {
            super(name);
            this.baozi = baozi;
        }
    
        @Override
        public void run() {
           while(true){
               synchronized (baozi){
                   if(baozi.flag==false){//没有包子
                       try {
    
                           baozi.wait();
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
    
                   }
                   //有包子
                   System.out.println("吃货正在吃包子");
                   baozi.flag=false;
                   baozi.notify();
    
               }
           }
    
        }
    }
    package com.thread;
    
    
    public class BaoZiPu extends Thread {
        private BaoZi baozi;
    
        public BaoZiPu(String name, BaoZi baozi) {
            super(name);
            this.baozi = baozi;
        }
    
        @Override
        public void run() {
            int count=0;
            //没有包子造
            while(true){
                synchronized (baozi){
                    if(baozi.flag==true){
                        try {
                            baozi.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //没有包子开始造
                    System.out.println("包子铺开始做包子");
                    baozi.flag=true;
                    baozi.notify();
    
                }
    
            }
    
            
    
    
        }
    }
  • 相关阅读:
    octotree神器 For Github and GitLab 火狐插件
    实用篇如何使用github(本地、远程)满足基本需求
    PPA(Personal Package Archives)简介、兴起、使用
    Sourse Insight使用过程中的常使用功能简介
    Sourse Insight使用教程及常见的问题解决办法
    github 遇到Permanently added the RSA host key for IP address '192.30.252.128' to the list of known hosts问题解决
    二叉查找树的C语言实现(一)
    初识内核链表
    container_of 和 offsetof 宏详解
    用双向链表实现一个栈
  • 原文地址:https://www.cnblogs.com/liushisaonian/p/11281013.html
Copyright © 2011-2022 走看看