进程和线程的几种通信方式

article/2025/9/24 18:42:26

进程之间通信的几种方式

1. 管道:是内核里面的一串缓存
管道传输的数据是单向的,若相互进行通信的话,需要进行创建两个管道才行的。
2. 消息队列:
例如,A进程给B进程发送消息,A进程把数据放在对应的消息队列后就可以正常的返回,B进程需要的时候再进行读取数据。
消息队列是保存在内存中的消息链表,在发送数据的时候,会分成一个独立的数据单元,即就是数据块,消息体是用户自定的数据 类型,消息的发送方和接收方要约定好消息体的数据类型,所以每个消息体都是固定大小的存储块,不像管道的无格式的字节流数据,注意的就是,消息队列中读取了消息体的话,内核就会把这个消息体给删除啦。
消息队列不适合比较大数据的传输,因为在内核中每个消息体都有一个最大长度的限制,同时所有队列所包含的全部消息体的总长度也是有上限。在 Linux 内核中,会有两个宏定义 MSGMAXMSGMNB,它们以字节为单位,分别定义了一条消息的最大长度和一个队列的最大长度。

消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销,因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。

3. 共享内存:
消息队列中的读取和写入的过程,都会有用户态和内核态之间的消息拷贝过程。共享内存的机制就是拿出一块虚拟化的地址空间来,映射到相同的物理内存中。这样这个进程写入东西,另外一个进程就可以看到了,大大提高了进程间通信的速度。
4. 信号量机制:
用了共享内存通信方式,带来新的问题,那就是如果多个进程同时修改同一个共享内存,很有可能就冲突了。例如两个进程都同时写一个地址,那先写的那个进程会发现内容被别人覆盖了。

为了防止多进程竞争共享资源,而造成的数据错乱,所以需要保护机制,使得共享的资源,在任意时刻只能被一个进程访问。正好,信号量就实现了这一保护机制。

信号量其实是一个整型的计数器,主要用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据
信号量表示资源的数量,控制信号量的方式有两种原子操作:

  • 一个是 P 操作,这个操作会把信号量减去 -1,相减后如果信号量 < 0,则表明资源已被占用,进程需阻塞等待;相减后如果信号量 >= 0,则表明还有资源可使用,进程可正常继续执行。
  • 另一个是 V 操作,这个操作会把信号量加上 1,相加后如果信号量 <= 0,则表明当前有阻塞中的进程,于是会将该进程唤醒运行;相加后如果信号量 > 0,则表明当前没有阻塞中的进程;

4. 信号:
对于异常的情况下的工作模式,需要用信号的方式来进行通知进程。
信号是进程间通信机制中的唯一的异步通信机制,任何时候给某一进程发送信息,一旦信号产生,就会有这几种的方式:
1、执行默认的操作
2、扑捉信号
3、忽略信号
5. socket:
管道、消息队列、共享内存、信号量和信号是在同一台主机上进行通信的,若想跨网络与不同的主机之间上的进程之间通信,需要用socket套接字啦

线程通信的几种方式

线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。

1. 等待通知机制

两个线程通过对同一对象调用等待 wait() 和通知 notify() 方法来进行通讯。

等待通知有着一个经典范式:

线程 A 作为消费者:

  1. 获取对象的锁。
  2. 进入 while(判断条件),并调用 wait() 方法。
  3. 当条件满足跳出循环执行具体处理逻辑。

线程 B 作为生产者:

  1. 获取对象锁。
  2. 更改与线程 A 共用的判断条件。
  3. 调用 notify() 方法。

伪代码如下:

//Thread Asynchronized(Object){while(条件){Object.wait();}//do something
}//Thread B
synchronized(Object){条件=false;//改变条件Object.notify();
}

2. join() 方法

在 join 线程完成后会调用 notifyAll() 方法,是在 JVM 实现中调用,所以这里看不出来。

3. volatile 共享内存

4. 管道通信

5. 并发工具

  1. CountDownLatch 并发工具
  2. CyclicBarrier 并发工具

Java中创建多线程的几种方式

在这里插入图片描述

方式1:

  1. 继承Thread类
class Number extends Thread{private static int num=1;@Overridepublic void run() {
//        for (int i = 0; i < 6; i++) {
//            System.out.println(Thread.currentThread().getName()+"\t"+i);
//            System.out.println("run thread");
//        }System.out.println(Thread.currentThread().getName());}
}
public class ThreadTest {public static void main(String[] args) {/*** 其实在这个地方需要注意的有*  一:start()方法是执行相应的准备,然后自动的启动执行run方法的内容调用 start() 方法,*          会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了*  二:run方法是:会把run方法当成一个main下面的普通的方法去执行的,并不会在某个线程中去执行它的,还是在主线程中进行执行的*/Number number1 = new Number();Number number2 = new Number();number1.start();System.out.println("======");number1.run();System.out.println("==========");number2.run();System.out.println("================");number2.start();}
}
在这个地方尤其是特别的注意start方法和run方法的,start是开启一个线程,然后会自动的执行run方法的,而run是在main方法下的一个普通的方法。

2、实现Runnable接口

class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}
}
public class RunnableTest  {public static void main(String[] args) {MyRunnable myRunnable = new MyRunnable();
//        myRunnable.run();Thread thread = new Thread(myRunnable);
//        thread.start();//结果为Thread0thread.run();//结果为main}
}

3、实现Callable接口的方式

class CallShare implements Callable<Integer> {@Overridepublic Integer call() throws Exception {System.out.println(Thread.currentThread().getName()+"Thread in callable");return 200;}
}
public class CallableTest {public static void main(String[] args) throws ExecutionException, InterruptedException {
//        CallableTest callableTest = new CallableTest();
//        Thread thread1 = new Thread(callableTest);//需要找一个中间的传递者进行接受这个
//        查找jdkapi可以看到关于有一个FutureTask中间类,实现其接口的有Runnable,此时我们可以利用此来进行书写Callable的多线程
//        注意,Runnable是有返回值的FutureTask<Integer> integerFutureTask = new FutureTask<Integer>(new CallShare());new Thread(integerFutureTask,"drjackxing ").start();System.out.println(integerFutureTask.get());System.out.println("================");//第二个多线程的实现FutureTask<Integer> integerFutureTask1 = new FutureTask<>(() -> {System.out.println(Thread.currentThread().getName() + "  come in callable");TimeUnit.SECONDS.sleep(4);return 1024;});new Thread(integerFutureTask1).start();System.out.println(integerFutureTask1.get());}
}

4、线程池的方式进行创建多线程
线程池的核心原理
线程池的核心参数的

ThreadPoolExecutor

 public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.acc = System.getSecurityManager() == null ?null :AccessController.getContext();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;}

1、corePoolSize指的是线程池中常驻的核心线程数

2、maximumPoolSize线程池中能够容纳同时执行的最大线程树,必须要大于1

3、keepAliveTime,多余的空闲c线程的存活时间,当前线程池中的数量超过了corePoolSize时,当前空闲时间达到keepAliveTime时候,多余的线程会被销毁到只剩下corePoolSize个线程为止

4、unit:keepAliveTime的单位

5、workQueue:任务队列,被提交但尚未被执行的任务

6、threadFactory:表示生成线程池中工作线程的线程工厂,
用于创建线程,一般默认的即可

7、handler:拒绝策略,表示当队列满了,并且工作线程大于
等于线程池的最大线程数(maximumPoolSize)时如何来拒绝
请求执行的runnable的策略

public class MyThreadPoolExcetorDemo {public static void main(String[] args) {new ThreadPoolExecutor(2,//核心的线程池5,//最大的线程池3L,//空闲的线程存活时间TimeUnit.SECONDS,//空闲线程存活的时间单位new ArrayBlockingQueue<>(3));//阻塞队列的个数}
}

线程池的底层工作原理
在这里插入图片描述
1、在创建了线程池后,线程池中的线程数为零。
2、当调用execute()方法添加一个请求任务时,线程池会做出如下判断:
2.1如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务;
2.2如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列;
2.3如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
2.4如果队列满了且正在运行的线程数量大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。
3、当一个线程完成任务时,它会从队列中取下一个任务来执行。
4、当一个线程无事可做超过一定的时间(keepAliveTime)时,线程会判断:
如果当前运行的线程数大于corePoolSize,那么这个线程就被停掉。

JDK中的拒绝策略

拒绝策略的条件:阻塞线程数+最大线程数已经满啦,无法再继续的创建啦

 //new ThreadPoolExecutor.AbortPolicy()//默认的发生异常的new ThreadPoolExecutor.DiscardOldestPolicy()//抛弃队列中等待最久的任务,然后把当前任务加人队列中尝试再次提交当前任务。
// new ThreadPoolExecutor.CallerRunsPolicy()//当前线程超过了最大线程数+阻塞线程数的时候就会进回退,调用则来进行执行任务
// new ThreadPoolExecutor.DiscardPolicy()//直接的抛弃多余的线程就好

一般在开发的过程中只要是默认就好的

线程池来创建Java多线程的方式

public class ThreadPoolDemo {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(2,//核心线程数5,//最大线程数2L, //保持线程的存活时间TimeUnit.SECONDS,//keepAliveTime的最大存活时间new ArrayBlockingQueue<>(3),//阻塞队列的线程的数Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());try {for (int i = 1; i <=10 ; i++) {executor.execute(()->{System.out.println(Thread.currentThread().getName()+"\t 开始办理业务");});}} catch (Exception e) {e.printStackTrace();} finally {executor.shutdown();}}
}

http://chatgpt.dhexx.cn/article/jmF9fbCu.shtml

相关文章

线程的几种通信方式

目录 一、Object的wait()、notify()、notifyAll()方法 二、Condition的await()、signal()、signalAll()方法 三、CountDownLatch 四、CyclicBarrier 五、Semaphore 线程间的通信方式常用的有如下几种&#xff1a; Object的wait()、notify()、notifyAll()方法&#xff1b; …

线程间的通信方法

线程间的通信方法 1. 线程通信简介 一般而言&#xff0c;在一个应用程序&#xff08;即进程&#xff09;中&#xff0c;一个线程往往不是孤立存在的&#xff0c;常常需要和其它线程通信&#xff0c;以执行特定的任务。如主线程和次线程&#xff0c;次线程与次线程&#xff0c…

Matlab基本操作函数 abs函数

分享一下我老师大神的人工智能教程&#xff01;零基础&#xff0c;通俗易懂&#xff01;http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章。分享知识&#xff0c;造福人民&#xff0c;实现我们中华民族伟大复兴&#xff01; 1、abs函数&#xff1a;数值的绝对值和复数…

MATLAB中FFT的整理

作为一个资深的健忘症患者&#xff0c;需要把每次用都忘记的FFT问题进行整理。 FFT可将信号从时域转换到频域。 首先是一些简单常识&#xff1a; 采样周期&#xff1a;两次采样之间的时间间隔。 采样频率&#xff1a;1/采样周期。每秒采样的点数。&#xff08;注意&#xff1a…

matlab中abs函数,matlababs是什么意思 是是是什么意思

matlababs是什么意思 是是是什么意思以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! matlab 中的abs函数什么意思 编程知识 matlab中的abs(x)是去绝对值的函数 例如:x=-1.23 abs(x) ans 1.23 以上即是取了-1.23…

Matlab 用法

MATLAB基础&#xff1a; 清除命令 clc 清空命令行的命令 clf 清除当前figure中的内容 clear 清除工作区变量 close all 关闭所有图形窗口 清除命令通常放在代码最前方&#xff0c;避免其他变量或代码的干扰 变量命名规则 ①以英文字母开头&#xff0c;可包含英文字母、…

abs 三种功能及代码详解 matlab函数

1.abs函数功能 求实数的绝对值、复数的模、字符串的ASCII值 2.基本用法 abs(x)函数是对数组元素进行绝对值处理的函数。 函数的定义域包括复数。 对于复数xab*i&#xff0c;有abs(x)sqrt(a2b2)。 3.代码 clc; clear all;a -7; b 12i; abs(a…

android 屏幕坐标总结

android 屏幕坐标好多个&#xff0c;有时候傻傻分不清楚&#xff0c;经常记错&#xff0c;然后只能一个个试。尴尬&#xff5e;&#xff5e; 把它们总结下来&#xff0c;以备不时之需嘿嘿。 一、视图坐标 最外面一层是屏幕&#xff0c;左上角是坐标原点&#xff0c;向右向…

【Unity3D】世界坐标与屏幕坐标

Unity3D由于是在三维世界中编程&#xff0c;而最终的结果是需要反馈到肉眼所示的2D屏幕之上的。这就产生了一种比较需要考虑的问题&#xff0c;尤其在一些涉及屏幕与Unity3D的3D世界交互的情况。网络上对于这方面的文字&#xff0c;大部分罗列了许许多多文字与代码或者API&…

Unity世界坐标转换屏幕坐标(测试)

下面展示一下上一篇说的两种实现方式打包文件在不同分辨率下的效果 1.WorldToScreenPoint 1920 * 1080 800 * 600 2.WorldToViewportPoint 1920 * 1080 800 * 600 总结 可以看到四种情况全部都显示正确&#xff0c;我们再看一下原来的代码 public Vector3 GetScreenPositio…

Unity 屏幕坐标转UI坐标

1&#xff1a;屏幕坐标转UI坐标 首先我们来明确下三个坐标概念&#xff1a; 世界坐标&#xff1a;指的是Transform组件的position字段 UI坐标&#xff1a;指的是RectTransform组件的anchoredPosition字段 屏幕坐标&#xff1a;指的是屏幕空间的坐标 (也可以说是相机空间的坐…

经纬度转换成屏幕坐标

学期projet总结&#xff1a; 当把点的数据和线的数据读进来之后&#xff0c;为了画出地图还有最重要的一步就是把实际的经纬度转换成屏幕像素点的坐标。在找老师讨论之前&#xff0c;我在网上查资料&#xff0c;找到了下边链接的文章&#xff0c;并按照这个方法画出了地图。 …

Unity-世界坐标与屏幕坐标

transform.position.x和transform.position.y的值含义是世界坐标。 世界坐标与屏幕坐标有时一样&#xff0c;有时不同&#xff0c;这和Canvas的渲染模式有关。 Canvas共有三种渲染模式 Screen Space - Overlay (此模式UGUI层一直在最上面&#xff0c;其他例如粒子等物体一直…

Unity 世界坐标、屏幕坐标、UGUI 坐标 相互转换

Unity 世界坐标、屏幕坐标、UGUI 坐标 相互转换 坐标转换是游戏开发过程中必不可少的环节 看下图 世界坐标、屏幕坐标、UI 坐标 三种坐标系的转换过程&#xff0c;此文章中的 UI 坐标特指 UGUI 坐标 从上图可以看到&#xff0c;世界坐标 和 UI 坐标 需要通过 屏幕坐标作为中间…

Android得到控件在屏幕中的坐标

getLocationOnScreen ,计算该视图在全局坐标系中的x,y值,(注意这个值是要从屏幕顶端算起,也就是索包括了通知栏的高度)//获取在当前屏幕内的绝对坐标 getLocationInWindow ,计算该视图在它所在的widnow的坐标x,y值,//获取在整个窗口内的绝对坐标 (不是很理解= =、) …

安卓 获取屏幕坐标(点击屏幕获取坐标)

工具下载&#xff1a; 实现原理&#xff1a;创建一个背景透明的Activity, 点击屏幕时获取坐标信息并显示。在悬浮窗中调用该Activity&#xff0c;可以获取所有界面的坐标信息。 package sc.tool.screen;import sc.tool.component.ActivityComponent; import android.content.Co…

Unity世界坐标转换屏幕坐标(详解)

我们先通过简单的操作实现一下基础的UI跟随物体移动的功能&#xff0c;首先我们在场景中建立一个Canvas并且添加一个图片作为按钮&#xff0c;之后我们添加一个3d物体作为跟随目标&#xff0c;效果如下图所示 我们配置一下UICanvas的属性&#xff0c;书写对应的自定义类并添加至…

地理坐标(经纬度坐标)和屏幕坐标(xy坐标)间的转换

在我们的屏幕上&#xff0c;有一张地图&#xff0c;这张地图经过缩放、平移、旋转&#xff0c;最终地理坐标和屏幕坐标的关系大致如下图所示&#xff1a; 这种关系要怎么描述呢&#xff1f;我们可以假设地图是一张纸&#xff0c;而屏幕是一堵墙。只要我们有两个图钉&#xff0c…

Windows的三种坐标系:屏幕坐标系,非客户区坐标系,客户区坐标系

1. 屏幕坐标系&#xff1a;以屏幕的左上角为原点&#xff0c;如图所示GetWindowRect() 函数获得的 RECT 就是以屏幕坐标系算的。 2. 非客户区坐标系(窗口坐标系)包括标题栏的部分。GetWindowDC 返回的设备环境就是基于此坐标系&#xff0c;一般只在 WM_NCPAINT 消息中使用。 3.…

Unity世界坐标系、本地坐标系、屏幕坐标系、视口坐标系

Unity中的坐标系 世界坐标系本地坐标系屏幕坐标系视口坐标系各个坐标系相互转换的API 世界坐标系 原点&#xff1a;世界的中心 轴向&#xff1a;世界坐标系的三个轴向是固定的 相关API: transform.position;transform.rotation; 四元数transform.eulerAngles; 欧拉角transfor…