Java 进阶(12) 线程通信

这篇具有很好参考价值的文章主要介绍了Java 进阶(12) 线程通信。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

多个线程在处理同⼀个资源,但是处理的动作(线程的任务)却不相同。

为什么要处理线程间通信

多个线程并发执⾏时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成⼀件任务,并且我们希望他们有规律的执⾏, 那么多线程之间需要⼀些协调通信,以此来帮我们达到多线程共同操作⼀份数据。

如何保证线程间通信有效利用资源

多个线程在处理同⼀个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同⼀个变量的使⽤或操作。 就是多个线程在操作同⼀份数据时, 避免对同⼀共享变量的争夺。也就是我们需要通过⼀定的⼿段使各个线程能有效的利⽤资源。⽽这种⼿段即—— 等待唤醒机制。

等待唤醒机制

什么是等待唤醒机制

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

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

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

线程通信方法

方法

说明

public final void wait()

释放锁,进⼊等待队列

public final void wait(long timeout)

在超过指定的时间前,释放锁,进⼊等待队列

public final void notify()

随机唤醒、通知⼀个线程

public final void notifyAll()

唤醒、通知所有线程

注意:所有的等待、通知⽅法必须在对加锁的同步代码块中。

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

1. wait:线程不再活动,不再参与调度,进⼊ wait set(锁池) 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态即是 WAITING。它还要等着别的线程执⾏⼀个特别的动作,也即是“通知(notify)”在这个对象上等待的线程从wait set 中释放出来,重新进⼊到调度队列(readyqueue)中wait(long m):wait⽅法如果在指定的毫秒之后,还没有被notify唤醒,就会⾃动醒来sleep(long m):不会释放锁

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

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

示例:

/*
等待唤醒案例:
1,创建⼀个顾客线程(消费者):告知⽼板要的包⼦种类和数量,调⽤wait⽅法,放弃cpu的执⾏,进⼊等待状态
2,创建⼀个⽼板线程(⽣产者):花了5秒做包⼦,做好包⼦之后,调⽤notify⽅法,通知顾客吃包⼦,
注意:
顾客和⽼板线程必须使⽤同步代码块包裹起来,保证等待和唤醒只能有⼀个在执⾏
同步使⽤的锁对象必须是唯⼀的,只有锁对象才能调⽤wait⽅法和notify⽅法
*/
public class Demo1 {
    public static void main(String[] args) {
        //创建锁对象,保证唯⼀
        Object obj =new Object();
        //创建顾客线程
        new Thread(){
            @Override
            public void run() {
                while(true){
                    //保证等待和唤醒只能有⼀个在执⾏
                    synchronized (obj){
                        System.out.println("告知⽼板要的包⼦种类和数量");
                        //进⼊等待
                        try {
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //唤醒之后执⾏的代码
                        System.out.println("拿到包⼦,开始吃。。。");
                        System.out.println("---------------------");
                    }
                }
            }
        }.start();
        //创建⽼板线程
        new Thread(){
            @Override
            public void run() {
                while(true){
                    //花5秒钟做包⼦,
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //保证等待和唤醒只能有⼀个在执⾏
                    synchronized (obj){
                        System.out.println("包⼦做好了。。。。");
                        //做好包⼦之后,调⽤notify⽅法,通知顾客吃包⼦,
                        obj.notify();
                    }
                }
            }
        }.start();
    }
}

注意:

哪怕只通知了⼀个等待的线程,被通知线程也不能⽴即恢复执⾏,因为它当初中断的地⽅是在同步块内,⽽此刻它已经不持有锁,所以她需要再次尝试去获取锁(很可能⾯临其它线程的竞争),成功后才能在当初调⽤ 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个⽅法。

 文章来源地址https://www.toymoban.com/news/detail-415539.html

到了这里,关于Java 进阶(12) 线程通信的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C# Socket通信从入门到精通(12)——多个同步UDP客户端C#代码实现

    我们在开发Udp客户端程序的时候,有时候在同一个软件上我们要连接多个服务器,这时候我们开发的一个客户端就不够使用了,这时候就需要我们开发出来的软件要支持连接多个服务器,最好是数量没有限制,这样我们就能应对任意数量的服务器连接,由于我们开发的Udp客户

    2024年02月04日
    浏览(55)
  • Webpack5入门到原理12:处理 Html 资源

    webpack.config.js 去掉引入的 js 文件,因为 HtmlWebpackPlugin 会自动引入 此时 dist 目录就会输出一个 index.html 文件

    2024年01月23日
    浏览(95)
  • Java多线程:进程与线程概述

    进程和线程 谈到多线程,就得先讲进程和线程的概念。 进程 进程可以理解为受操作系统管理的基本运行单元。360浏览器是一个进程、WPS也是一个进程,正在操作系统中运行的\\\".exe\\\"都可以理解为一个进程 线程 进程中独立运行的子任务就是一个线程。像QQ.exe运行的时候就有很

    2023年04月09日
    浏览(43)
  • Java多线程系列——概述

    简介 在计算机编程中,多线程是一种重要的概念,允许程序同时执行多个任务,提高程序的效率和性能。Java作为一门广泛应用于软件开发的编程语言,也提供了丰富的多线程支持。本文将简要介绍Java多线程的基本概念、使用方法以及相关特性。 为什么使用多线程? 多线程

    2024年02月20日
    浏览(35)
  • 高级进阶多线程——多任务处理、线程状态(生命周期)、三种创建多线程的方式

    Java中的多线程是一个同时执行多个线程的进程。线程是一个轻量级的子进程,是最小的处理单元。多进程和多线程都用于实现多任务处理。 但是,一般使用多线程而不是多进程,这是因为线程使用共享内存区域。它们不分配单独的内存区域以节省内存,并且线程之间的上下

    2024年02月13日
    浏览(39)
  • QT之串口通信和多线程处理

    使用QT的多线程编程,完成串口通信助手的设计。 使用QT5.12中自带的QSerialPort和QSerialPortInf的类实现对串口硬件的访问,通过对类的方法进行操作,完成整个串口的控制。整个操作基于类的实例,能够快速部署。这里需要明确层次的概念。串口类,提供了整个串口通信需要的方

    2024年02月07日
    浏览(32)
  • 【linux 多线程并发】多线程模型下的信号通信处理,与多进程处理的比较,属于相同进程的线程信号分发机制

    ​ 专栏内容 : 参天引擎内核架构 本专栏一起来聊聊参天引擎内核架构,以及如何实现多机的数据库节点的多读多写,与传统主备,MPP的区别,技术难点的分析,数据元数据同步,多主节点的情况下对故障容灾的支持。 手写数据库toadb 本专栏主要介绍如何从零开发,开发的

    2024年01月17日
    浏览(46)
  • EPOLL单线程版本 基于reactor 的 httpserver文件下载 支持多个客户端同时处理

    之前写了一个httpserver的问价下载服务器    如果有多个客户端请求过来只能串行处理必须得等当前的操作完成之后才会处理    另外还存在 文件大的时候 会出错 处理不了  原因就是 sendfile是在一个while循环中处理的   当调用send失败返回-1之后 就  结束了   而一般来讲 

    2024年02月07日
    浏览(54)
  • Java入门12(多线程)

    继承 Thread 类:一旦继承了 Thread 类,就不能再继承其他类了,可拓展性差 实现 Runnable 接口:仍然可以继承其他类,可拓展性较好 使用线程池 继承Thread 类 ​不能通过线程对象调用 run() 方法,需要通过 t1.start() 方法,使线程进入到就绪状态,只要进入到就绪状态的线程才有

    2024年02月13日
    浏览(36)
  • java死锁、线程状态、线程通信、线程池

    java实现多线程: [1]继承Thread类并重写run方法 [2]实现Runnable接口 线程Thread中常用的方法: setName(): Thread.currentThread().getName(): ​ static void sleep(); static void yield(): join(): setDeamon()设置后台线程 线程安全问题: ---当多个线程共享同一个资源时,对该资源的操作就会出现线程安全问题。

    2024年02月13日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包