IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java多线程-07 (线程通信中的 “等待/通知” 机制) -> 正文阅读

[Java知识库]Java多线程-07 (线程通信中的 “等待/通知” 机制)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 线程通信? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?个人博客:www.xiaobeigua.icu


1.1 等待/通知机制

1.1.1 什么是等待通知机制

????????在单线程编程中,要执行的操作需要满足一定的条件才能执行,可 以把这个操作放在 if语句快中。

????????在多线程编程中,可能 A 线程的条件没有满足只是暂时的, 稍后其 他的线程 B 可能会更新条件使得 A 线程的条件得到满足. 可以将 A 线 程暂停,直到它的条件得到满足后再将 A线程唤醒,这就是通知/等待机制

它的伪代码:

atomics{ //原子操作
    while( 条件不成立 ){
        等待
    }
    当前线程被唤醒条件满足后,继续执行下面的操作
}

1.1.2 等待/通知机制的实现

????????Object 类中的 wait()方法可以使执行当前代码的线程等待,暂停执 行,直到接到通知或被中断为止.

????????注意:

????????????????1) wait()方法只能 在同步代码块中由锁对象调用

????????????????2) 调用 wait()方法,当前线程会释放

????????其伪代码如下:

//在调用 wait()方法前获得对象的内部锁
synchronized( 锁对象 ){
    while( 条件不成立 ){
        //通过锁对象调用 wait()方法暂停线程
        锁对象.wait();
    }
    //线程的条件满足了继续向下执行
}

????????Object 类的 notify()或者notifyAll()可以唤醒线程,该方法也必须在同步代码块中 由锁对象调 用 。没 有 使 用 锁 对 象 调 用 wait()/notify() 会抛出 IlegalMonitorStateExeption 异常。

????????如果有多个等待的线程,notify()方法 只能唤醒其中的一个. 在同步代码块中调用 notify()方法后,并不会立即释放锁对象,需要等当前同步代码块执行完后才会释放锁对象,一般 将 notify()方法放在同步代码块的最后. 它的伪代码如下:

synchronized( 锁对象 ){
    //执行修改保护条件 的代码
    //唤醒其他线程
    锁对象.notify();
}

例子:

????????定义两个线程 线程1用于模拟等待? ? 线程2用于激活线程1

package com.xiaobeigua.one;
/**
 * 作者:小北呱
 */
public class test3 {

    public static void main(String[] args)  {
        //定义一个引用变成作为synchronized (lock)的参数
        String lock="lock";
        //线程1 等待
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    System.out.println("线程1开始等待.....");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程1被线程2激活,结束等待!");
                }

            }
        }).start();

        //线程2 激活
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    System.out.println("线程2开始激活线程1....");
                    lock.notify();
                    System.out.println("线程2激活结束!");
                }
            }
        }).start();
    }
}

结果:

????????

?注意:从运行结果可以看出 使用notify()方法后不会立即释放锁对象,而是要执行完这个同步代码块里的语句后才会释放锁对象。

1.1.3?interrupt()方法会中断 wait()

????????当线程处于 wait()等待状态时, 调用线程对象的 interrupt()方法会 中断线程的等待状态, 会产生 InterruptedException 异常

代码

package com.xiaobeigua.one;
/**
 * 作者:小北呱
 */
public class test3 {

    public static void main(String[] args) throws InterruptedException {
        //定义一个引用变成作为synchronized (lock)的参数
        String lock="lock";
        //线程1 等待
      Thread t1=  new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lock){
                    System.out.println("线程1开始等待.....");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("线程1等待状态被interrupt()中断了,结束等待!");
                }

            }
        });

      //开启线程1 让其进去等待状态
      t1.start();

      Thread.sleep(1000);
      //调用其interrupt()方法
      t1.interrupt();




    }
}

结果:

????????

1.1.4? notify()与 notifyAll()

????????notify()一次只能唤醒一个线程,如果有多个等待的线程,只能随机 唤醒其中的某一个; 想要唤醒所有等待线程,需要调用 notifyAll()。

?例子:创建 4个线程? 线程 0 1 2 开启等待? ?线程3 使用 notify()

package com.xiaobeigua.one;
/**
 * 作者:小北呱
 */
public class test3 {

    public static void main(String[] args){
        MyRunable1 myRunable1=new MyRunable1();
        MyRunable2 myRunable2=new MyRunable2();

        Thread t1=new Thread(myRunable1);
        Thread t2=new Thread(myRunable1);
        Thread t3=new Thread(myRunable1);

        Thread t4=new Thread(myRunable2);

        t1.start();
        t2.start();
        t3.start();

        t4.start();

    }





    //内部静态类 创建等待和激活两个方法 供两个线程类调用
    static class MyLock{
        static String  lock="lock";

        public static void beWith() throws InterruptedException {
            synchronized (lock){
                System.out.println(Thread.currentThread().getName()+"开始等待...");
                lock.wait();
                System.out.println(Thread.currentThread().getName()+"被激活,结束等待");
            }
        }

        public static   void enWith() throws InterruptedException {
            synchronized (lock){
                System.out.println(Thread.currentThread().getName()+"开始激活...");
                lock.notify();
                System.out.println(Thread.currentThread().getName()+"激活结束!");
            }
        }
    }

    //创建等待线程类
    static   class MyRunable1 implements Runnable{

        @Override
        public void run() {
            try {
                MyLock.beWith();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //创建notify线程类
    static class MyRunable2 implements Runnable{

        @Override
        public void run() {
            try {
                MyLock.enWith();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

结果:

????????

?和预想一样,线程 0 1 2都进入了等待状态 线程3开始激活 调用 notify()方法 只激活的线程0

?将代码中的notify()方法 改为 notifyAll()结果:

????????

?可以看到 线程3调用 notifyAll()方法 全部激活了线程

1.1.5?wait(long)的使用

wait(long)带有 long 类型参数的 wait()等待,如果在参数指定的时间 内没有被唤醒,超时后会自动唤醒。

package com.xiaobeigua.one;

public class Test {

    public static void main(String[] args)  {

        new Thread(new Runnable() {
            @Override
            public synchronized void run() {
                System.out.println("开始进入等待状态....");
                try {
                    //等待2秒
                    this.wait(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("时间到 退出等待");
            }
        }).start();


    }
}

结果:

注意:

????????线程 wait()等待后,可以调用 notify()唤醒线程, 如果 notify()唤醒的 过早,在等待之前就调用了 notify()可能会打乱程序正常的运行逻

1.1.6?生产者消费者模式

????????在 Java 中,负责产生数据的模块是生产者,负责使用数据的模块是 消费者. 生产者消费者解决数据的平衡问题,即先有数据然后才能使用,没有数据时,消费者需要等待

?例子:到店里次牛排? ?生产者生产牛排 最多 10块? 消费者吃牛排? 全部吃完再通知生产者再生产

????????

注意:这里的类全部以 内部类形式出现

package com.xiaobeigua.one;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * 作者:小北呱
 */
public class test3 {

    public static void main(String[] args) {
        MyRunable1 myRunable1 = new MyRunable1();
        MyRunable2 myRunable2 = new MyRunable2();
        //创建生产者
        Thread t0 = new Thread(myRunable1);
        //创建消费者
        Thread t1 = new Thread(myRunable2);

        t0.start();
        t1.start();


    }


    //产品类
    static class MyProduct {

        //设置list集合容量为10 相当于 桌子只能放十块牛排
        static List list = new ArrayList();

        //生产牛排
        public static void setPro() throws InterruptedException {

            //当桌面上没有牛排时,生产者开始生产牛排
            synchronized (list) {
                while (list.size() <= 10) {

                    String pro = "牛排" + new Random();
                    list.add(pro);
                    System.out.println(Thread.currentThread().getName() + "生产了牛排" + pro);
                    //当牛排满10块时,停止生产
                }

                list.notify();
            }
        }

        //消费牛排
        public static void getpro() throws InterruptedException {

            synchronized (list) {
                while (list.size() != 0) {
                    System.out.println(Thread.currentThread().getName() + "吃了" + list.remove(list.size() - 1));
                }
                list.wait();
            }
        }


    }

    //创建生产线程类
   static class MyRunable1 implements Runnable {
        test3.MyProduct myProduct = new test3.MyProduct();

        @Override
        public void run() {
            try {
                myProduct.setPro();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    //创建消费线程类
    static class MyRunable2 implements Runnable {
        test3.MyProduct myProduct = new test3.MyProduct();

        @Override
        public void run() {
            try {
                myProduct.getpro();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}





?结果:

?这里只是简单的实现了生产者与消费者模式,主要是理解它的设计思想为我所用

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-08 11:07:41  更:2021-08-08 11:08:44 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/10 11:49:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码