首页 > 其他分享 >线程间通信

线程间通信

时间:2023-03-18 13:13:58浏览次数:42  
标签:线程 变量 间通信 volatile 内存 保证

参考:

https://zhuanlan.zhihu.com/p/452313580

https://zhuanlan.zhihu.com/p/34362413

https://zhuanlan.zhihu.com/p/151289085

https://www.cnblogs.com/bearbrick0/p/15904552.html

介绍

线程启动后,它会在自己独有的栈空间里面运行,但是实际上,两个线程之间是会相互通信的,因为只有这样才能使线程间更加灵活,使资源使用的更加充分。

多线程之间相互协调完成工作的过程叫线程间通信。

可见性

可见性是指:当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。

背景:

两个线程对同一个共享变量进行操作,其中一个线程对其修改,另外一个线程是看不到这个变化的。
由jvm内存模型决定,内存模型分为共享区域和线程私有区域,线程启动后会把共享区域(主内存区)的变量作为副本存到自己内部(工作内存区),而工作内存的数据不会实时刷到主内存,所以当线程修改变量时,只是对自己生效,其他线程并不会感知到,看下图:

 

 线程对变量的所有操作都必须在工作内存中进行而不能直接操作主内存的变量

不同线程之间也无法直接访问对方工作内存中的变量

线程间变量值的传递均需通过主内存来完成

 

 主内存与工作内存的交互遵守及一定的协议

Java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这种依赖主内存作为传递媒介的方式来实现可见性的

无论是普通变量还是volatile变量都是如此,普通变量与volatile变量的区别是,volatile的特殊规则保证了新值能立即同步到主内存,以及每次使用前立即从主内存刷新。因此,可以说volatile保证了多线程操作时变量的可见性,而普通变量则不能保证这一点。

 

volatil

保证对一个变量的更新能够立马被其他线程看到

当一个变量被声明为volatile时,线程在写入变量时不会把值缓存在寄存器或者其他地方,而是会把值刷新回主内存。

当其他线程读取该共享变量时,会从主内存重新获取最新值,而不是使用当前线程的工作内存中的值。

Java内存模型对volatile专门定义了一些特殊的访问规则,当一个变量定义为volatile之后,它将具备两种特性。
  1. 保证此变量对所有线程的可见性,即当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。而普通变量不能做到这一点,普通变量的值在线程间传递均需要通过主内存来完成,例如,线程A修改一个普通变量的值,然后向主内存进行回写,另外一条线程B在线程A回写完成了之后再从主内存进行读取操作,新变量值才会对线程B可见。
  2. 禁止指令重排序优化。普通的变量仅仅会保证在该方法的执行过程中所有依赖赋值结果的地方都能获取到正确的结果,而不能保证变量赋值操作的顺序与程序代码中的执行顺序一致。因为在一个线程的方法执行过程中无法感知到这点,这也就是Java内存模型中描述的所谓的“线程内表现为串行的语义”(Within-Thread As-If-Serial Semantics)。

只能保证可见性,不能保证原子性(需要通过加锁保证原子性)

能够禁止指令重排,在一定程度上保证代码有序性

 

线程间通信方式

主要分为共享内存消息传递(也叫等待-通知)和管道流

共享内存:线程间读写共享内存中的公共数据实现间接通信,比如 volatile 保证内存的可见性

消息传递:线程之间没有公共的状态,线程之间必须通过明确的发送信息来显示的进行通信。比如 wait/notify/notifyAll等待通知方式和join方式。

管道流:管道流是是一种使用比较少的线程间通信方式,管道输入/输出流和普通文件输入/输出流或者网络输出/输出流不同之处在于,它主要用于线程之间的数据传输,传输的媒介为管道。比如 管道输入/输出。管道通信就是使用java.io.PipedInputStream 和 java.io.PipedOutputStream进行通信。像消息传递机制,也就是说:通过管道,将一个线程中的消息发送给另一个。

 

标签:线程,变量,间通信,volatile,内存,保证
From: https://www.cnblogs.com/deity-night/p/17229760.html

相关文章

  • 为什么用线程池?解释一下线程池参数?
    1、降低资源消耗;提高线程利用率,降低创建和销毁线程的消耗。2、提高响应速度;任务来了,直接有线程可用可执行,而不是先创建线程,再执行3、提高线程的可管控性;线程是稀缺资源,使......
  • 为什么用线程池?解释一下线程池参数?
    1、降低资源消耗;提高线程利用率,降低创建和销毁线程的消耗。2、提高响应速度;任务来了,直接有线程可用可执行,而不是先创建线程,再执行3、提高线程的可管控性;线程是稀缺资源,使......
  • 谈谈ConcurrentHashMap是如何保证线程安全的?
    jdk1.7中是采用Segment+HashEntry+ReentrantLock的方式进行实现的,而1.8中放弃了Segment臃肿的设计,取而代之的是采用Node+CAS+Synchronized来保证并发安全进行实现......
  • 守护线程
    packageedu.wtbu;//测试守护线程//上帝守护你publicclassDemo07{publicstaticvoidmain(String[]args){Godgod=newGod();Youyou=new......
  • 线程的优先级
    packageedu.wtbu;//测试线程的优先级publicclassDemo06{publicstaticvoidmain(String[]args){//Thread.MAX_PRIORITY=10//Thread.Min_PRIOR......
  • 线程停止
    packageedu.wtbu;publicclassDemo01implementsRunnable{//1.设置一个标识位privatebooleanflag=true;@Overridepublicvoidrun(){inti......
  • 说一下线程池内部工作原理(ThreadPoolExecutor)
    ThreadPoolExecutor构造方法的参数corePoolSize:线程池的核心线程数,说白了就是,即便是线程池里没有任何任务,也会有corePoolSize个线程在候着等任务。maximumPoolSize:最大......
  • 进程和线程
    进程、线程1进程与线程的关系和区别什么是进程定义:进程是一个具有一定独立功能的程序在一个数据集合上依次动态执行的过程。进程是一个正在执行的程序的实例,包括程序......
  • 线程执行顺序
    线程执行顺序在做面试题的时候,发现有关线程执行顺序的一个常见考题:(纯纯考研审题)packagelink;publicclassTest{publicstaticvoidmain(String[]args){......
  • C# 多线程task
    C#多线程task1.异步和多线程的区别?没什么太大区别。异步是目的,使用多线程实现。想想AJAX异步加载,不就是不想让浏览器界面卡住嘛,所以在程序中对于某些单独的操作,比如写......