多线程编程-- part 4 线程间的通信
线程间的相互作用
线程之间需要一些协调通信,来共同完成一件任务。
Object类相关的方法:notify(),notifyAll(),wait()。会被所有的类继承,这些方法是final不能被重写。他们操控的是每个对象都会有的锁,如果不在synchronized里面调用wait,notify,notifyAll方法,运行时会报异常:要调用对象的这些方法,必须先获得这个对象的锁。
wait():
使得当前线程必须等待,进入到等待序列,等到另外一个线程调用notify()或者notifyAll()激活
当前线程必须拥有当前对象的monitor,就是锁。线程调用wait(),释放对锁的拥有权,等待另外的线程来通知他,这样才能重新获得锁的拥有权和恢复执行。
要确保调用wait()方法的时候拥有锁。
调用Object.wait()方法,会释放对象的锁。调用Thread.sleep()方法,不会释放对象的锁。
notify():
唤醒一个等待当前对象的锁的线程,如果多个线程在等待,他们中的一个将会被选择唤醒,这种选择是随意的。
被唤醒的锁是不能被执行的,必须要等到当前线程放弃这个对象的锁,被唤醒的线程和其他线程竞争锁。
一个线程拥有一个对象的锁有以下几种方法:
1.执行这个对象的synchronized实例方法
2.执行这个对象的synchronized语句块,这个语句块锁的是这个对象
3.对于class类的对象,执行那个类的synchronized static方法
学到线程通信就必须看看经典例子:生产/消费问题
- 生产者在仓库未满的时候生产,仓库满则停止生产
- 消费者仅仅在仓库有产品的时候才能消费,仓空则等待
- 消费者发现仓库没产品消费时,通知生产者等待
- 生产者在生产处可消费产品时,通知等待的消费者去消费
初步设计:
1.Depot是“仓库”类,仓库中记录“仓库的容量(capacity)”以及“仓库中当前产品数目(size)”。
“仓库”类的生产方法produce()和消费方法consume()方法都是synchronized方法,进入synchronized方法体,意味着这个线程获取到了该“仓库”对象的同步锁。这也就是说,同一时间,生产者和消费者线程只能有一个能运行。通过同步锁,实现了对“仓库”的互斥访问。
produce()方法:仓库满时,生产者线程进入等待,生产完成,通过nofityAll()唤醒所有的线程,consume()方法:消费者进行消费之后,会通过nofityAll()方法通知生产者进行生产
2.Producer类:生产者类,每次会新建一个线程调用仓库的produce()方法进行生产
3.Customer类:消费者类,每次会新建一个线程调用仓库的consume()方法进行消费
4.定义若干次消费和生产,看是不是满足关系
package com.template.ProduceConsume; /**
* <生产者和消费者>
* <详细介绍>
*
* @author 姬国靖
* @since 设计wiki | 需求wiki
*/
public class test {
public static void main(String[] args) {
Depot mDepot = new Depot(100);
Producer mPro = new Producer(mDepot);
Customer mCus = new Customer(mDepot); mPro.produce(60);
mPro.produce(120);
mCus.consume(90);
mCus.consume(150);
mPro.produce(110);
}
} //仓库
class Depot {
private int capacity; // 仓库的容量
private int size; // 仓库的实际数量 public Depot(int capacity) {
this.capacity = capacity;
this.size = 0;
} public synchronized void produce(int val) {
try {
// left 表示“想要生产的数量”(有可能生产量太多,需多此生产)
int left = val;
while (left > 0) {
// 库存已满时,等待“消费者”消费产品。
while (size >= capacity)
wait();
// 获取“实际生产的数量”(即库存中新增的数量)
// 如果“库存”+“想要生产的数量”>“总的容量”,则“实际增量”=“总的容量”-“当前容量”。(此时填满仓库)
// 否则“实际增量”=“想要生产的数量”
int inc = (size+left)> capacity ? (capacity-size) : left;
size += inc;
left -= inc;
System.out.printf("%s produce(%3d) --> left=%3d, inc=%3d, size=%3d\n",
Thread.currentThread().getName(), val, left, inc, size);
// 通知“消费者”可以消费了。
notifyAll();
}
} catch (InterruptedException e) {
}
} public synchronized void consume(int val) {
try {
// left 表示“客户要消费数量”(有可能消费量太大,库存不够,需多此消费)
int left = val;
while (left > 0) {
// 库存为0时,等待“生产者”生产产品。
while (size <= 0)
wait();
// 获取“实际消费的数量”(即库存中实际减少的数量)
// 如果“库存”<“客户要消费的数量”,则“实际消费量”=“库存”;
// 否则,“实际消费量”=“客户要消费的数量”。
int dec = (size<left) ? size : left;
size -= dec;
left -= dec;
System.out.printf("%s consume(%3d) <-- left=%3d, dec=%3d, size=%3d\n",
Thread.currentThread().getName(), val, left, dec, size);
notifyAll();
}
} catch (InterruptedException e) {
}
} public String toString() {
return "capacity:"+capacity+", actual size:"+size;
}
} //生产者
class Producer {
private Depot depot; public Producer(Depot depot) {
this.depot = depot;
} // 消费产品:新建一个线程向仓库中生产产品。
public void produce(final int val) {
new Thread() {
public void run() {
depot.produce(val);
}
}.start();
}
} //消费者
class Customer {
private Depot depot; public Customer(Depot depot) {
this.depot = depot;
} // 消费产品:新建一个线程从仓库中消费产品。
public void consume(final int val) {
new Thread() {
public void run() {
depot.consume(val);
}
}.start();
}
}

分析:可以看出仓库满时停止生产,等待消费者通知,不够消费停止消费,,等待生产者通知
多线程编程-- part 4 线程间的通信的更多相关文章
- java多线程详解(6)-线程间的通信wait及notify方法
Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New) ...
- Java 多线程(七) 线程间的通信——wait及notify方法
线程间的相互作用 线程间的相互作用:线程之间需要一些协调通信,来共同完成一件任务. Object类中相关的方法有两个notify方法和三个wait方法: http://docs.oracle.com/ ...
- iOS开发多线程篇—线程间的通信
iOS开发多线程篇—线程间的通信 一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任 ...
- iOS边练边学--多线程NSOperation介绍,子类实现多线程的介绍(任务和队列),队列的取消、暂停(挂起)和恢复,操作依赖与线程间的通信
一.NSOperation NSOperation和NSOperationQueue实现多线程的具体步骤 先将需要执行的操作封装到一个NSOperation对象中 然后将NSOperation对象添加 ...
- Java多线程中线程间的通信
一.使用while方式来实现线程之间的通信 package com.ietree.multithread.sync; import java.util.ArrayList; import java.u ...
- iOS开发多线程篇 04 —线程间的通信
iOS开发多线程篇—线程间的通信 一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任 ...
- Java基础教程:多线程基础(2)——线程间的通信
Java基础教程:多线程基础(2)——线程间的通信 使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控与监督. 线程间的通信 ...
- Java并发编程(04):线程间通信,等待/通知机制
本文源码:GitHub·点这里 || GitEE·点这里 一.概念简介 1.线程通信 在操作系统中,线程是个独立的个体,但是在线程执行过程中,如果处理同一个业务逻辑,可能会产生资源争抢,导致并发问题, ...
- Java核心知识点学习----多线程并发之线程间的通信,notify,wait
1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...
随机推荐
- 编译openwrt时报错build_dir/hostpkg/libubox-2018-07-25-c83a84af/blobmsg_json.c:21:19: fatal error: json.h: No such file or directory
答: 一. 详细日志: build_dir/hostpkg/libubox-2018-07-25-c83a84af/blobmsg_json.c:21:19: fatal error: json.h: ...
- 文笔很差系列4 - Kris Kremo
转载请标注原链接 https://www.cnblogs.com/xczyd/p/11127671.html Kris Kremo老先生(1951年出生,1970年第一次正式登台,截止2019年练习时 ...
- 算法试题 - 找出最小 k 个数
题目 题目:输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. 解析 思路1 这一题应用堆排序算法复杂度只有O(nlog k), ...
- 安卓之Android.mk编写
题记:编译环境可以参考https://www.cnblogs.com/ywjfx/p/9960817.html 不管是写C还是java,我想所有的程序员都经历过HelloWorld程序的编写,现在让我 ...
- PHP 生成器 yield理解
如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显.但是,生成 ...
- react中路由跳转push与replace的区别
路由跳转,replace / push 区别 push: a-b-c 可以回到上一级 例: this.props.history.push('路由地址') replace: a-b-c 回不到上一级 ...
- HDWIKI6.0后台SQL写shell
- VS附加到进程调试
WIN+R 进入cmd命令 输入 netstat -ano | find "进程端口" 找端口 打开vs alt+d+p选择上图对应的进程
- 【BZOJ4668】冷战(并查集)
Description 1946 年 3 月 5 日,英国前首相温斯顿·丘吉尔在美国富尔顿发表"铁幕演说",正式拉开了冷战序幕.美国和苏联同为世界上的"超级大国" ...
- [转帖]ORA-00600-[kcratr_nab_less_than_odr]问题小记
ORA-00600-[kcratr_nab_less_than_odr]问题小记 2018年03月12日 20:56:57 我不是VIP 阅读数 1500 https://blog.csdn.ne ...