Java并发编程的艺术(七)——线程间的通信
为什么需要线程间通信
让线程之间合作,提高运行效率。
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
作用
- 让多个并发的线程串行执行。
- 当A线程调用B.jion(),那么,A会等待B结束后,再从jion继续执行。
- 如果被等待的线程执行很长的时间,那么join会抛出InterruptedException。当调用B.interrupt()之后,jion函数就会抛出异常。
实现原理
- join的底层采用wait() 方法进行停止运行。
- 然后当被等待线程终止后,会调用线程的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并发编程的艺术(七)——线程间的通信的更多相关文章
- Java并发编程的艺术(六)——线程间的通信
多条线程之间有时需要数据交互,下面介绍五种线程间数据交互的方式,他们的使用场景各有不同. 1. volatile.synchronized关键字 PS:关于volatile的详细介绍请移步至:Java ...
- java并发编程(十一)线程间的通信notify通知的遗漏
notify通知的遗漏很容易理解,即threadA还没开始wait的时候,threadB已经notify了,这样,threadB通知是没有任何响应的,当threadB退出synchronized代码块 ...
- Java并发编程的艺术(七)——Executors
Executors框架简介 Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动.执行和关闭,可以简化并发 ...
- Java并发编程(八)线程间协作(上)
多线程并发执行时,不同的线程执行的内容之间可能存在一些依赖关系,比如线程一执行a()方法和c()方法,线程二执行b()方法,方法a()必须在方法b()之前执行,而方法c()必须在方法b()之后执行.这 ...
- Java并发编程(十三)线程间协作的两种方式:wait、notify、notifyAll和Condition
在现实中,需要线程之间的协作.比如说最经典的生产者-消费者模型:当队列满时,生产者需要等待队列有空间才能继续往里面放入商品,而在等待的期间内,生产者必须释放对临界资源(即队列)的占用权.因为生产者如果 ...
- Java并发编程(九)线程间协作(下)
上篇我们讲了使用wait()和notify()使线程间实现合作,这种方式很直接也很灵活,但是使用之前需要获取对象的锁,notify()调用的次数如果小于等待线程的数量就会导致有的线程会一直等待下去.这 ...
- Java并发编程的艺术(十一)——线程池(2)
Executor两级调度模型 在HotSpot虚拟机中,Java中的线程将会被一一映射为操作系统的线程. 在Java虚拟机层面,用户将多个任务提交给Executor框架,Executor负责分配线程执 ...
- Java并发编程的艺术(四)——线程的状态
线程的状态 初始态:NEW 创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态. 运行态:RUNNABLE 在Java中,运行态包括就绪态 和 运行态. 就绪态 该状态下的线 ...
- Java并发编程的艺术(十)——线程池(1)
线程池的作用 减少资源的开销 减少了每次创建线程.销毁线程的开销. 提高响应速度 每次请求到来时,由于线程的创建已经完成,故可以直接执行任务,因此提高了响应速度. 提高线程的可管理性 线程是一种稀缺资 ...
- Java并发编程的艺术(十)——线程池
线程池的作用 降低资源消耗.重复利用已有线程,减少线程的创建和销毁造成的消耗. 提高响应速度.当有任务需要处理的时候,就不用再花费重新创建线程的时间了. 提高线程的可管理性.不合理利用线程,会浪费资源 ...
随机推荐
- Spring源码之Bean生命周期
https://www.jianshu.com/p/1dec08d290c1 https://www.cnblogs.com/zrtqsk/p/3735273.html 总结 将class文件加载成B ...
- 使用qmake编译时拷贝文件
使用qmake构建项目时,需要在make时拷贝一些文件到指定位置,非执行make install,下面总结列举一下我了解的方式 COPIES 示例pro 1 COPY_DIR = $$PWD/copy ...
- arm-linux 修改rootfs登录名和密码
1.保证文件系统busybox中已经配置了login登录功能. 2.修改命令行前缀名 (1)进到/etc/sysconfig,找到HOSTNAME文件,修改里面为想要的登录名后,之后再重新加载文件系统 ...
- JavaScript监听页面可见性(焦点)同时改变title的三种方法
JavaScript监听页面可见性(焦点)同时改变title的三种方法 本文参考了https://developer.mozilla.org/zh-CN/docs/Web/API/Page_Visib ...
- Redis未授权访问漏洞复现与利用
漏洞简介 Redis默认情况下,会绑定在0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源ip访问等,这样将会将Redis服务暴露到公网上,如果在没有设置密码认 ...
- powershell过杀软工具-xencrypt
在红队攻击中,绕杀软是一个比较常见的技术.对于绕过杀软的方法,有基于黑白名单的,有基于shellloader的,也有基于加密与混淆的.最近在发现了这样一款过杀软的工具,推荐给有缘人,嘻嘻 ...
- linux的time命令
查看程序执行时间
- 使用Beyond Compare对比大篇幅文件的小技巧
我们在编辑较大篇幅的文章时,无可避免地要经过多次的修改.有时候修改的版本过多时,我们很可能就会记不清最新版的文章对比上一版的文章,究竟修改了哪些地方.但有了Beyond Compare(Windows ...
- ABBYY FineReader 14创建PDF文档功能解析
使用ABBYY FineReader,您可以轻松查看和编辑任何类型的 PDF,真的是一款实至名归的PDF编辑转换器,您知道的,它能够保护.签署和编辑PDF文档,甚至还可以创建PDF文档,本文和小编一起 ...
- 如何用MathType 7输入连续几个数的和
在数学的学习中,我们经常需要使用求和符合来求连续几个数的和,那么作为专业的公式编辑器,如何输入连续几个数的求和呢? 具体步骤如下: 步骤一 打开专业的公式编辑软件MathType 7,用鼠标点击上方的 ...