iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Java线程间通信方式
  • 558
分享到

Java线程间通信方式

javajvm开发语言android 2023-09-24 09:09:16 558人浏览 泡泡鱼
摘要

前文了解了线程的创建方式和状态切换,在实际开发时,一个进程中往往有很多个线程,大多数线程之间往往不是绝对独立的,比如说我们需要将A和B 两个线程的执行结果收集在一起然后显示在界面上,又或者比较典型的消

前文了解了线程的创建方式和状态切换,在实际开发时,一个进程中往往有很多个线程,大多数线程之间往往不是绝对独立的,比如说我们需要将A和B 两个线程的执行结果收集在一起然后显示在界面上,又或者比较典型的消费者-生产者模式,在这些场景下,线程间通信成了我们必须使用的手段,那么线程之间怎么通信呢?

线程间通信方式,从实现本质来讲,主要可以分为两大类共享内存和消息传递。

相信大家还记得,在内存模型一节,我们提到多线程并发情况下的三大特性,原子性,有序性,可见性,其所对应的解决方案就可以用来实现线程间通信,这些解决方案的本质就是共享内存。

对于消息传递而言,最经典的实现就是我们的Handler机制,在子线程使用主线程的Handler对象将一些信息发送到主线程以便进行处理。

下面我们来看一些线程间通信的典型实现

Object.wait/Object.notify

对于Object对象而言,其提供了等待/通知机制以便实现线程间通信,由于Object是Java中所有类的父类,也就意味着Java中所有对象都支持通知/等待机制,与该机制关联的主要有五个方法:

方法名称描述备注
wait()线程执行中调用对象的wait方法可以使得当前线程进入WAITING状态,只有等待其他线程的通知或被中断才会返回,需要注意的是,调用wait方法后,会释放对象的/
wait(long timeout)与wait含义一致,不同的是通过timeout指定了超时时间,如果时间到了还没收到通知就超时返回/
wait(long timeout, int nanos)超时管控更加精确,第二个参数单位为毫微秒/
notify通知一个在对象上等待的线程使其从wait对象返回/
notifyAll通知所有等待在该对象上的线程/

以Object.wait/Object.notify实现一个典型的消息者生产者模型,消费者对变量做-1操作,生产者对变量做+1操作,代码如下:

// 盘子public class Number {    // 盘子当前容量,是否有内容    private int mCount = 0;      //对盘子容量进行+1操作    public void inc() {        if (mCount != 0) {            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        mCount++;        System.out.println(Thread.currentThread().getName()+",mCount+1,mCount="+mCount);        this.notifyAll();    }    //对盘子容量进行-1操作    public void dec() {        if (mCount == 0) {            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        mCount--;        System.out.println(Thread.currentThread().getName()+",mCount-1,mCount="+mCount);        this.notifyAll();    }}
    public static void main(String[] args) {        Number number = new Number();        // 生产者线程        Thread incThread = new Thread(new Runnable() {            @Override            public void run() {                number.inc();            }        });        incThread.setName("Inc Thread");        incThread.start();        // 消费者线程        Thread decThread = new Thread(new Runnable() {            @Override            public void run() {                number.dec();            }        });        decThread.setName("Dec Thread");        decThread.start();    }

如上述代码备注,其中Inc Thread为生产者线程,当盘子内容为0时,每次向盘子Number中放一个内容,消费者线程Dec Thread当盘子有内容时,消耗内容,让盘子内容变为0.运行输出如下:

1-4-3-1

糟糕,正确运行一个循环后,抛出了IllegalMonitorStateException,为什么会这样呢?这个异常是什么意思?

遇事不决看源码,IllegalMonitorStateException的类说明如下:

Thrown to indicate that a thread has attempted to wait on an object’s monitor or to notify other threads waiting on an object’s monitor without owning the specified monitor.

翻译过来的意思就是当线程在没有持有特定的锁的情况下试图等待对象锁或者通知其他线程等待对象锁会抛出此异常,有点拗口,先放置,即然我们调用了wait/notifyAll这两个方法,不妨看下这两个方法的说明,看是否有新的提示,wait方法说明如下:

public final void wait() throws InterruptedException {    wait(0);}

在上述说明中反复提到 The current thread must own this object’s monitor. This method should only be called by a thread that is the owner of this object’s monitor.也就是说在调用Object.wait方法前,当前线程必须持有该对象的锁,获取锁的方法很简单,wait方法说明中也有,通过synchronized关键词,那么正确的调用代码如下所示:

public class Number {    private int mCount = 0;    public void inc() {        synchronized (this) {            if (mCount != 0) {                try {                    this.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            mCount++;            System.out.println(Thread.currentThread().getName()+",mCount+1,mCount="+mCount);            this.notifyAll();        }    }    public void dec() {        synchronized (this) {            if (mCount == 0) {                try {                    this.wait();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            mCount--;            System.out.println(Thread.currentThread().getName()+",mCount-1,mCount="+mCount);            this.notifyAll();        }    }}

重新运行代码,输出如下:

1-4-3-2

这里可以看出,只运行了一个循环,那么怎么让它一直运行呢?将if修改称while即可,以生产10次为例,如需一直生产消息,使用while(true)即可,代码及输出如下:

public class Number {    private int mCount = 0;    private int mIncTimes = 0;    private int mDecTimes = 0;    public void inc() {        synchronized (this) {            while (mIncTimes < 10) {                if (mCount != 0) {                    try {                        this.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                mCount++;                mIncTimes ++;                System.out.println(Thread.currentThread().getName()+",mCount+1,mCount="+mCount+",mIncTimes:"+mIncTimes);                this.notifyAll();            }        }    }    public void dec() {        synchronized (this) {            while (mDecTimes < 10) {                if (mCount == 0) {                    try {                        this.wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }                mCount--;                mDecTimes++;                System.out.println(Thread.currentThread().getName()+",mCount-1,mCount="+mCount+",mDecTimes:"+mDecTimes);                this.notifyAll();            }        }    }}

1-4-3-3

综上,使用Object.wait/Object.notify/Object.notifyAll时,切记其必须先使用关键词获取同个Object的对象锁,否则就会抛出IllegalMonitorStateException异常

Semaphore

Semaphore翻译为信号量,一个信号量维护一组许可,在调用acquire方法时阻塞,直到获取许可,在调用release的时候释放占用,从而唤醒阻塞的某个线程。信号量操作类似于停车场车辆管理,初始时停车场有5个车位,当停车场内部5个车位全占满时,此时可用资源为0,即信号量可用许可数量为0,其他车辆想停车就只能在停车场外排队阻塞(相当于调用acquire),当一辆车辆从停车场驶出时(相当于调用release方法),此时信号量许可数量为1,唤醒一个等待停车的车辆进入停车辆,自身可用许可数量再次为0,依此往复。

对于只有一个许可的信号量而言,其可用许可数量为0或1,故被称为二进制信号量,对于有多个正整数可用许可数据的信号量而言,其被称为通用信号量。需要注意在执行acquire时信号量本身并不会持有同步锁,因为这样会影响被释放的许可进入可用许可池中。

二进制信号量,不同于其他锁机制,要求释放锁的线程和获取锁的线程是同一个,也就意味着我们可以在其他线程释放二进制信号量以完成死锁恢复。

下面我们以二进制信号量实现消费者生产者模式,代码如下(生产消费4次即停止):

public class Counter {    private int mCount = 0;    public void incCount() {        mCount ++;    }    public void decCount() {        mCount--;    }    public int getCount() {        return mCount;    }}// Main主类代码private static int mIncTimes = 0;public static void main(String[] args) {    Counter counter = new Counter();    Semaphore semaphore = new Semaphore(1);    Thread incThread = new Thread(new Runnable() {        @Override        public void run() {            while (mIncTimes < 4) {                try {                    semaphore.acquire();                    if (counter.getCount() == 0) {                        counter.incCount();                        mIncTimes ++;                        System.out.println("Inc Thread ++,current count is:" + counter.getCount());                    }                } catch (InterruptedException e) {                    e.printStackTrace();                } finally {                    semaphore.release();                }            }        }    });    incThread.setName("Inc Thread");    incThread.start();    Thread decThread = new Thread(new Runnable() {        @Override        public void run() {            while (mIncTimes < 4) {                try {                    semaphore.acquire();                    if (counter.getCount() != 0) {                        counter.decCount();                        System.out.println("Dec Thread --,current count is:" + counter.getCount());                    }                } catch (InterruptedException e) {                    e.printStackTrace();                } finally {                    semaphore.release();                }            }        }    });    decThread.setName("Dec Thread");    decThread.start();}

运行结果如下:

1-4-3-6

内存一致性影响,要求一个线程中的release操作和另一个线程中的acquire操作必须存在happen-before关系

来源地址:https://blog.csdn.net/u010132993/article/details/130353846

--结束END--

本文标题: Java线程间通信方式

本文链接: https://www.lsjlt.com/news/416804.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java线程间通信方式
    前文了解了线程的创建方式和状态切换,在实际开发时,一个进程中往往有很多个线程,大多数线程之间往往不是绝对独立的,比如说我们需要将A和B 两个线程的执行结果收集在一起然后显示在界面上,又或者比较典型的消...
    99+
    2023-09-24
    java jvm 开发语言 android
  • 浅谈Java线程间通信方式
    目录1.volatile和synchronized关键字2.等待/通知机制3.管道输入/输出流4.join()方法5.ThreadLocal()方法总结线程间通信方式有两种:共享内存...
    99+
    2024-04-02
  • Java线程通信之wait-notify通信方式详解
    目录1.线程通信的定义2.为什么需要wait-notify3.wait方法和notify方法1、对象的wait()方法2、对象的notify()方法4.wait方法和notify方法...
    99+
    2024-04-02
  • java线程间通信的方法是什么
    Java线程间通信的方法有以下几种: 使用共享变量:多个线程共享同一个变量,通过对变量的读写操作来实现线程间的通信。例如,一个线程...
    99+
    2023-10-28
    java
  • Java线程通信中wait-notify通信的方式是什么
    这篇文章主要介绍“Java线程通信中wait-notify通信的方式是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java线程通信中wait-notify通信的方式是什么”文章能帮助大家解决问...
    99+
    2023-06-29
  • Java通过wait()和notifyAll()方法实现线程间通信
    本文实例为大家分享了Java实现线程间通信的具体代码,供大家参考,具体内容如下Java代码(使用了2个内部类):package Threads;import java.util.LinkedList;public class ProdCon...
    99+
    2023-05-31
    java wait notifyall
  • Python进程间通信方式
    目录一、通信方式二、Queue介绍三、方法介绍三、生产者和消费者模型四、什么是生产者消费者模式实现方式一:Queue实现方式二:利用JoinableQueue一、通信方式 进程彼此之...
    99+
    2024-04-02
  • 线程通信的四种方式
    多个线程在并发执行的时候,他们在CPU中是随机切换执行的,这个时候我们想多个线程一起来完成一件任务,这个时候我们就需要线程之间的通信了,多个线程一起来完成一个任务,线程通信一般有4种方式: 通过 vo...
    99+
    2023-09-05
    java
  • Java并发编程之线程间的通信
    目录一、概念简介1、线程通信2、等待通知机制3、基础方法二、等待通知原理1、基本原理2、实现案例三、管道流通信1、管道流简介2、使用案例四、生产消费模式1、业务场景2、代码实现五、源...
    99+
    2024-04-02
  • 浅谈Java线程间通信之wait/notify
    Java中的wait/notify/notifyAll可用来实现线程间通信,是Object类的方法,这三个方法都是native方法,是平台相关的,常用来实现生产者/消费者模式。先来我们来看下相关定义:wait() :调用该方法的线程进入WA...
    99+
    2023-05-31
    java 线程wait notify
  • 详谈java线程与线程、进程与进程间通信
    线程与线程间通信一、基本概念以及线程与进程之间的区别联系:关于进程和线程,首先从定义上理解就有所不同1、进程是什么?是具有一定独立功能的程序、它是系统进行资源分配和调度的一个独立单位,重点在系统调度和单独的单位,也就是说进程是可以独 立运行...
    99+
    2023-05-31
    进程 线程 通信
  • Linux进程间通信的方式
    这篇文章主要介绍“Linux进程间通信的方式”,在日常操作中,相信很多人在Linux进程间通信的方式问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux进程间通信的方式”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-16
  • android实现线程间通信的四种常见方式
    1,通过Handler机制 主线程中定义Handler,子线程发消息,通知Handler完成UI更新,Handler对象必须定义在主线程中,如果是多个类直接互相调用,就不是很方便,...
    99+
    2024-04-02
  • 深入探究一下Java中不同的线程间数据通信方式
    目录1、多线程如何共享数据2、子线程如何继承父线程数据3、相关问题1、多线程如何共享数据 多线程数据共享可以分为以下2种情况,线程实现代码相同及线程实现代码不同。 线程实现代码相同 ...
    99+
    2023-05-16
    Java线程数据通信方式 Java线程数据通信 Java线程通信 Java线程
  • 怎么在java中实现线程间通信
    这篇文章将为大家详细讲解有关怎么在java中实现线程间通信,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以...
    99+
    2023-05-30
    java
  • Java学习之线程同步与线程间通信详解
    目录线程同步的概念同步代码块同步方法线程组线程组的相关方法线程组对象的基本应用线程间的通信线程通信简单应用线程同步的概念 由于同一个进程的多个线程共享同一块存储空间,在带来方便的同时...
    99+
    2022-12-27
    Java线程同步 Java线程通信 Java线程
  • 进程间的通信方式(六种)
    进程之间的通信 参考文章:https://blog.csdn.net/qq_34827674/article/details/107678226 前提知识:每个进程都有自己的用户空间,而内核空间是每个进程共享的。因此进程之间想要进行通信,...
    99+
    2023-08-18
    linux 运维 服务器 进程线程
  • android线程间怎么通信
    在Android中,线程间通信可以通过以下几种方式实现:1. Handler:可以通过Handler对象在不同的线程之间发送消息。每...
    99+
    2023-08-19
    android
  • Java中怎么实现线程间通信与信号量
    Java中怎么实现线程间通信与信号量,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1.信号量Semaphore先说说Semaphore,Semaphore可以控制某个资源可...
    99+
    2023-05-30
    java
  • android线程间通信的方法有哪些
    Android线程间通信的方法有以下几种:1. Handler:Handler是Android中最常用的线程间通信方式。它可以将消息...
    99+
    2023-08-26
    android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作