26.线程间的通信

线程通信确保多线程在共享资源时协调工作,主要方式包括共享内存(如volatile关键字)、消息传递(wait/notify、join)和管道输入/输出流。wait/notify机制用于线程间等待与通知,join方法让主线程等待子线程完成,而管道流提供线程间的数据传输通道。
摘要由CSDN通过智能技术生成

线程间通信

线程的通信可以被定义为:

线程通信就是当多个线程共同操作共享的资源时,互相告知自己的状态以避免资源争夺。

为什么需要线程通信

线程是操作系统调度的最小单位,有自己的栈空间,可以按照既定的代码逐步的执行,但是如果每个线程间都孤立的运行,那就会造资源浪费。所以在现实中,我们需要这些线程间可以按照指定的规则共同完成一件任务,所以这些线程之间就需要互相协调,这个过程被称为线程的通信。

线程通信的方式

线程通信主要可以分为三种方式,分别为共享内存消息传递管道流。每种方式有不同的方法来实现

  • 共享内存:线程之间共享程序的公共状态,线程之间通过读-写内存中的公共状态来隐式通信。

volatile共享内存

  • 消息传递:线程之间没有公共的状态,线程之间必须通过明确的发送信息来显示的进行通信。

wait/notify等待通知方式
join方式

  • 管道流

管道输入/输出流的形式

共享内存

共享内存这种方式比较常见,我们经常会设置一个共享变量。然后多个线程去操作同一个共享变量。从而达到线程通讯的目的。

例如:我们使用多个线程去执行页面抓取任务,我们可以使用一个共享变量count来记录任务完成的数量。每当一个线程完成抓取任务,会在原来的count上执行加1操作。这样每个线程都可以通过获取这个count变量来获得当前任务的完成情况。当然必须要考虑的是共享变量的同步问题,这也共享内存容易出错的原因所在。

如果线程A要和线程B通信,则需要经过以下步骤:
①线程A把本地内存A更新过的共享变量刷新到主内存中
②线程B到内存中去读取线程A之前已更新过的共享变量。

这保证了线程间的通信必须经过主内存。下面引出我们要学习的关键字volatile
volatile有一个关键的特性:保证内存可见性,即多个线程访问内存中的同一个被volatile关键字修饰的变量时,当某一个线程修改完该变量后,需要先将这个最新修改的值写回到主内存,从而保证下一个读取该变量的线程取得的就是主内存中该数据的最新值,这样就保证线程之间的透明性,便于线程通信。
代码实现:
A、B线程分别对值进行运算,加到50结束

public class VolatileTest {
   
	private   static volatile int flag = 0; 
	public static void main(String[] args) {
   
		// 线程A
		new Thread(new Runnable() {
   
			@Override
			public void run() {
   
				while(true) {
   
					if(flag <= 50) {
   
						 synchronized (VolatileTest.class) {
   
							 System.out.println("线程A" + flag);
								flag ++;
							} 
						
						try {
   
							Thread.sleep(1000);
						} catch (InterruptedException e) {
   
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}else break;
				}
			}
			
		}).start();;
		
		// 线程B
		new Thread(new Runnable() {
   
			@Override
			public void run() {
   
				while(true) {
   
					if(flag <= 50) {
   
						 synchronized (VolatileTest.class) {
   
							 System.out.println("线程B" + flag);
								flag ++;
							} 
						try {
   
							Thread.sleep(1000);
						} catch (InterruptedException e) {
   
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}else break;
				}
			}
		}).start();;
	}
}

测试结果:
在这里插入图片描述

这种通讯模型中,不同的线程之间是没有直接联系的。都是通过共享变量这个中间人来进行交互。而这个中间人必要情况下还需被保护在临界区内(加锁或同步)。由此可见,一旦共享变量变得多起来,并且涉及到多种不同线程对象的交互,这种管理会变得非常复杂,极容易出现死锁等问题。

消息传递

消息传递方式采取的是线程之间的直接通信,不同的线程之间通过显式的发送消息来达到交互目的。

wait/notify等待通知方式

从字面上理解,等待通知机制就是将处于等待状态的线程将由其它线程发出通知后重新获取CPU资源,继续执行之前没有执行完的任务。最典型的例子生产者--消费者模式

在这里插入图片描述
有一个产品队列,生产者想要在队列中添加产品,消费者需要从队列中取出产品,如果队列为空,消费者应该等待生产者添加产品后才进行消费,队列为满时,生产者需要等待消费者消费一部分产品后才能继续生产。队列可以认为是java模型里的临界资源,生产者和消费者认为是不同的线程,它们需要交替的占用临界资源来进行各自方法的执行,所以就需要线程间通信。

生产者--消费者模型主要为了方便复用和解耦,java语言实现线程之间的通信协作的方式是等待/通知机制
等待/通知机制提供了三个方法用于线程间的通信:

  • wait()方法:中断方法的执行,使线程等待
  • notify()方法:唤醒处于等待的某一个线程,使其他结束等待
  • notifyAll()方法:唤醒所有处于等待的线程,使它们结束等待

线程间的通信需要对象Object来完成,对象中的wait()、notify()、notifyAll()方法就如同开关信号,用来完成等待方和通知方的交互。

生产者与消费者

容器类:

public class Queue {
   
	private int n;
	/*
	 * 用于判断容器中是否有值
	 * 若有值,则消费,生产者等待,反之则生产,消费者等待,
	 */
	boolean flag 
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空 白

停止的只会是自己,你得追逐世界

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值