为什么需要线程间通信

让线程之间合作,提高运行效率。

volatile和synchronized关键字

实现原理

这两个方式都是采用共享内存的方式进行通信,通过同步机制保证数据可见性和排他性。

特点

  • 本质是数据共享。
  • 不能特定地传给某个线程数据,需要程序员自己编写逻辑。数据在各个线程的更新顺序由操作系统决定。
  • 不能过多使用,这样会降低程序执行效率。

使用案例

// 用于控制线程当前的执行状态
private volatile boolean flag = false; // 开启一条线程
Thread t1 = new Thread(new Runnable(){
void run(){
// 开关
while(!flag){
Thread.sleep(1000);
}
// 执行线程任务
doSometing();
}
}).start(); // 开始执行
public void start(){
flag = true;
}

这里通过volatile修饰的标志位flag实现其他线程对t1的控制。

等待和通知机制

等待/通知是Java实现多个进程交替协作的机制。

实现方法

Java提供了API实现该机制。

使用注意

  • 上述所有方法都必须放在一个同步块中。
  • 上述方法都只能由所处同步块的锁对象调用。
  • 调用notify()方法之后,只是将线程从等待队列中转移到阻塞队列,当线程得到锁之后,才能用wait()方法之后,继续执行程序。

经典范式

该范式分为两个部分,分别针对等待方(消费者)和通知方(生产者)。

生产者通过notify唤醒消费者。消费者通过wait等待生产者生产完毕。

生产者:

private volatile boolean flag = false;

synchronized(objectA) {
flag = true;
objectA.notify();
}

消费者:

synchronized(objectA) {
while(!flag) {
objectA.wait();
} doSomething();
}

超时等待

为了避免等待方无止境地等待,可以通过超时等待,跳出等待。

public void get(long mills){
synchronized( list ){
// 不加超时功能
if ( mills <= 0 ) {
while( list.isEmpty() ){
list.wait();
}
} // 添加超时功能
else {
boolean isTimeout = false;
while(list.isEmpty() && isTimeout){
list.wait(mills);
isTimeout = true;
} // doSometing……
}
}
}

代码中利用list作为中间变量装载数据。

管道流

什么是管道流

用于线程间的数据传输。传输媒介为内存。

实现方式

管道输入输出主要包括四种具体实现:PipedOutputStream、PipedInputStream、PipedWriter、PipedReader。分别对应字节流和字符流。

// 创建输入流与输出流对象
PipedWriter out = new PipedWriter();
PipedReader in = new PipedReader(); // 连接输入输出流
out.connect(in); // 创建写线程
class WriteThread extends Thread{
private PipedWriter out; public WriteThread(PipedWriter out){
this.out = out;
} public void run(){
out.write("lippon");
}
} // 创建读线程
class ReaderThread extends Thread{
private PipedReader in; public ReaderThread(PipedReader in){
this.in = in;
} public void run(){
in.read();
}
}

Thread.join

作用

  1. 让多个并发的线程串行执行。
  2. 当A线程调用B.jion(),那么,A会等待B结束后,再从jion继续执行。
  3. 如果被等待的线程执行很长的时间,那么join会抛出InterruptedException。当调用B.interrupt()之后,jion函数就会抛出异常。

实现原理

  1. join的底层采用wait() 方法进行停止运行。
  2. 然后当被等待线程终止后,会调用线程的notifyAll() 方法释等待队列中的线程。

实现方式

public static void main(String[] args){

    // 开启一条线程
Thread t = new Thread(new Runnable(){
public void run(){
// doSometing
}
}).start(); // 调用join,等待t线程执行完毕
try{
t.join();
}catch(InterruptedException e){
// 中断处理……
}
}

Java并发编程的艺术(七)——线程间的通信的更多相关文章

  1. Java并发编程的艺术(六)——线程间的通信

    多条线程之间有时需要数据交互,下面介绍五种线程间数据交互的方式,他们的使用场景各有不同. 1. volatile.synchronized关键字 PS:关于volatile的详细介绍请移步至:Java ...

  2. java并发编程(十一)线程间的通信notify通知的遗漏

    notify通知的遗漏很容易理解,即threadA还没开始wait的时候,threadB已经notify了,这样,threadB通知是没有任何响应的,当threadB退出synchronized代码块 ...

  3. Java并发编程的艺术(七)——Executors

    Executors框架简介 Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动.执行和关闭,可以简化并发 ...

  4. Java并发编程(八)线程间协作(上)

    多线程并发执行时,不同的线程执行的内容之间可能存在一些依赖关系,比如线程一执行a()方法和c()方法,线程二执行b()方法,方法a()必须在方法b()之前执行,而方法c()必须在方法b()之后执行.这 ...

  5. Java并发编程(十三)线程间协作的两种方式:wait、notify、notifyAll和Condition

    在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权.因为生产者如果 ...

  6. Java并发编程(九)线程间协作(下)

    上篇我们讲了使用wait()和notify()使线程间实现合作,这种方式很直接也很灵活,但是使用之前需要获取对象的锁,notify()调用的次数如果小于等待线程的数量就会导致有的线程会一直等待下去.这 ...

  7. Java并发编程的艺术(十一)——线程池(2)

    Executor两级调度模型 在HotSpot虚拟机中,Java中的线程将会被一一映射为操作系统的线程. 在Java虚拟机层面,用户将多个任务提交给Executor框架,Executor负责分配线程执 ...

  8. Java并发编程的艺术(四)——线程的状态

    线程的状态 初始态:NEW 创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态. 运行态:RUNNABLE 在Java中,运行态包括就绪态 和 运行态. 就绪态 该状态下的线 ...

  9. Java并发编程的艺术(十)——线程池(1)

    线程池的作用 减少资源的开销 减少了每次创建线程.销毁线程的开销. 提高响应速度 每次请求到来时,由于线程的创建已经完成,故可以直接执行任务,因此提高了响应速度. 提高线程的可管理性 线程是一种稀缺资 ...

  10. Java并发编程的艺术(十)——线程池

    线程池的作用 降低资源消耗.重复利用已有线程,减少线程的创建和销毁造成的消耗. 提高响应速度.当有任务需要处理的时候,就不用再花费重新创建线程的时间了. 提高线程的可管理性.不合理利用线程,会浪费资源 ...

随机推荐

  1. 加解密 C语言实现

    1.加密的基本原理 加密分为对称加密和非对称加密,对称加密就是加密方和解密放用同一个密钥. 加密是分组加密,即将明文数据分成多个密钥大小的块,依次和密钥运算,输出密文. padding,由于加密需要分 ...

  2. nacos服务注册源码解析

    1.客户端使用 compile 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2.2.3.RELEASE' compi ...

  3. 微软面试题: LeetCode 4. 寻找两个正序数组的中位数 hard 出现次数:3

    题目描述: 给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2.请你找出并返回这两个正序数组的中位数. 进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决 ...

  4. 面试官:小伙子,说一说Java多线程有哪些创建方式吧

    第一种 继承Thread类 自定义类,继承Thread类,并重写run()方法. class MyThread1 extends Thread { @Override public void run( ...

  5. 如何用FL Studio做电音

    电音制作,自然少不了适合做电音的软件,市面上可以进行电音制作的软件不少,可是如果在这些软件中只能选择一款的话,想必多数人会把票投给FL Studio,毕竟高效率是永远不变的真理,今天就让我们来看看如何 ...

  6. jQuery 第四章 实例方法 DOM操作_基于jQuery对象增删改查相关方法

    .next() .prev() .nextAll() .prevAll() .prevUntil() .nextUntli() .siblings() .children() .parent() .p ...

  7. Java蓝桥杯——贪心算法

    贪心算法 贪心算法:只顾眼前的苟且. 即在对问题求解时,总是做出在当前看来是最好的选择 如买苹果,专挑最大的买. 最优装载问题--加勒比海盗 货物重量:Wi={4,10,7,11,3,5,14,2} ...

  8. 记一次Ddos遭遇

    万年不用的vps最近借朋友用了几天,今天突然跟我说连不上了 上服务器先暴力重启一波 还是不行,netstat一看 端口的连接状态是这个样子: 估计连接被打满了,遂换了个端口 重启之 问题解决

  9. 机场&代理商-关系图

    机场&代理商-关系图 思路 ①首先统计机场活跃度Top10的机场名称,以下是我的表结构,以及查询语句 表结构: 查询语句:SELECT * from 2020csale ORDER BY cn ...

  10. Appium上下文和H5测试(二)

    坚持原创输出,点击蓝字关注我吧 作者:清菡 博客:oschina.云+社区.知乎等各大平台都有. 文章总览图 一.往期回顾 loc='new UiSelector().text("全程班&q ...