java 多线程间通信(一)
synchronized同步
package com.test7;
public class Run {
public class MyObject {
private int a;
public MyObject(int a) {
this.a = a;
}
synchronized public void methodA() {
System.out.println("run methodA" + this.a);
this.a = 10;
}
}
public class ThreadA extends Thread {
private MyObject object;
public ThreadA(MyObject object) {
this.object = object;
}
@Override
public void run() {
object.methodA();
}
}
public class ThreadB extends Thread {
private MyObject object;
public ThreadB(MyObject object) {
this.object = object;
}
// 省略构造方法
@Override
public void run() {
object.methodA();
}
}
public static void main(String[] args) {
Run r = new Run();
MyObject object = r.new MyObject(5);
// 线程A与线程B 持有的是同一个对象:object
ThreadA a = r.new ThreadA(object);
ThreadB b = r.new ThreadB(object);
a.start();
b.start();
}
}
run methodA5
run methodA10
多个线程需要访问同一个共享变量、方法,谁拿到了锁(获得了访问权限),谁就可以执行。
wait/notify机制
package com.test7;
import java.util.ArrayList;
import java.util.List;
public class Test {
static public class MyList {
private static List<Integer> list = new ArrayList<Integer>();
public static void add(int i) {
list.add(i);
}
public static int size() {
return list.size();
}
}
public class ThreadA extends Thread {
private Object lock;
public ThreadA(Object lock) {
super();
this.lock = lock;
}
@Override
public void run() {
try {
synchronized (lock) {
if (MyList.size() != 5) {
System.out.println("wait begin "
+ System.currentTimeMillis());
lock.wait();
System.out.println("Interruption!!!");
lock.notify();
lock.wait();
System.out.println("wait end "
+ System.currentTimeMillis());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadB extends Thread {
private Object lock;
public ThreadB(Object lock) {
super();
this.lock = lock;
}
@Override
public void run() {
try {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
MyList.add(i);
if (MyList.size() == 5) {
lock.notify();
System.out.println("已经发出了通知");
lock.wait();
}
System.out.println("添加了" + (i + 1) + "个元素!");
System.out.println(MyList.list.toString());
Thread.sleep(1000);
}
lock.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
try {
Test t = new Test();
Object lock = new Object();
ThreadA a = t.new ThreadA(lock);
a.start();
Thread.sleep(50);
ThreadB b = t.new ThreadB(lock);
b.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
wait begin 1535596248129
添加了1个元素!
[0]
添加了2个元素!
[0, 1]
添加了3个元素!
[0, 1, 2]
添加了4个元素!
[0, 1, 2, 3]
已经发出了通知
Interruption!!!
添加了5个元素!
[0, 1, 2, 3, 4]
添加了6个元素!
[0, 1, 2, 3, 4, 5]
添加了7个元素!
[0, 1, 2, 3, 4, 5, 6]
添加了8个元素!
[0, 1, 2, 3, 4, 5, 6, 7]
添加了9个元素!
[0, 1, 2, 3, 4, 5, 6, 7, 8]
添加了10个元素!
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
wait end 1535596258180
线程A要等待某个条件满足时(list.size()==5),才执行操作。线程B则向list中添加元素,改变list 的size。
A,B之间如何通信的呢?也就是说,线程A如何知道 list.size() 已经为5了呢?
这里用到了Object类的 wait() 和 notify() 方法。
当条件未满足时(list.size() !=5),线程A调用wait() 放弃CPU,并进入阻塞状态。不像while轮询那样占用CPU资源。
当条件满足时,线程B调用 notify()通知 线程A,所谓通知线程A,就是唤醒线程A,并让它进入可运行状态。
这种方式的一个好处就是CPU的利用率提高了。
管道通信
管道流主要用来实现两个线程之间的二进制数据的传播,下面以PipedInputStream类和PipedOutputStream类为例,实现生产者-消费者:
package com.test7;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class PipeTest {
/**
* 我们以数字替代产品 生产者每5秒提供5个产品,放入管道
*/
class MyProducer extends Thread {
private PipedOutputStream outputStream;
private int index = 0;
public MyProducer(PipedOutputStream outputStream) {
this.outputStream = outputStream;
}
@Override
public void run() {
while (true) {
try {
for (int i = 0; i < 5; i++) {
index++;
System.out.println("放入产品:" + index);
outputStream.write(index);
}
} catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 消费者每0.5秒从管道中取1件产品,并打印剩余产品数量,并打印产品信息(以数字替代)
*/
class MyConsumer extends Thread {
private PipedInputStream inputStream;
public MyConsumer(PipedInputStream inputStream) {
this.inputStream = inputStream;
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
int count = inputStream.available();
if (count > 0) {
System.out.println("剩余产品数量: " + count);
System.out.println("得到产品: " + inputStream.read());
} else {
System.out.println("未取到产品");
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
public static void main(String[] args) {
PipeTest t = new PipeTest();
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream();
try {
pis.connect(pos);
} catch (IOException e) {
e.printStackTrace();
}
t.new MyProducer(pos).start();
t.new MyConsumer(pis).start();
}
}
放入产品:1
放入产品:2
放入产品:3
放入产品:4
放入产品:5
剩余产品数量: 5
得到产品: 1
剩余产品数量: 4
得到产品: 2
剩余产品数量: 3
得到产品: 3
剩余产品数量: 2
得到产品: 4
剩余产品数量: 1
得到产品: 5
未取到产品
未取到产品
未取到产品
未取到产品
未取到产品
放入产品:6
放入产品:7
放入产品:8
放入产品:9
放入产品:10
剩余产品数量: 5
得到产品: 6
剩余产品数量: 4
得到产品: 7
剩余产品数量: 3
得到产品: 8
剩余产品数量: 2
得到产品: 9
剩余产品数量: 1
得到产品: 10
...
java 多线程间通信(一)的更多相关文章
- Java 多线程间通信
JDK 1.5 以后, 将同步和锁封装成了对象, 并将操作锁的隐式方法定义到了该对象中, 将隐式动作变成了显示动作. Lock 接口 Lock 接口, 位于 java.util.concurrent. ...
- java 多线程间通信(二)
传统的线程通信 Object提供了三个方法wait(), notify(), notifyAll()在线程之间进行通信,以此来解决线程间执行顺序等问题. wait():释放当前线程的同步监视控制器,并 ...
- Java多线程间通信-解决安全问题、等待唤醒机制
/*1.增加一个知识点一个类怎么在所有的类中,让其它类来共同修改它的数据呢?可以用单例设计模式可以用静态可以在其它类中做一个构造函数,接受同一个对象,这样就可以实现对象 2.状态选择可以用数字0 1 ...
- Java线程间通信-回调的实现方式
Java线程间通信-回调的实现方式 Java线程间通信是非常复杂的问题的.线程间通信问题本质上是如何将与线程相关的变量或者对象传递给别的线程,从而实现交互. 比如举一个简单例子,有一个多线程的 ...
- (十一)boost库之多线程间通信
(十一)boost库之多线程间通信 1.互斥锁 在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性.每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一 ...
- Java 多线程间的通讯
在前一小节,介绍了在多线程编程中使用同步机制的重要性,并学会了如何实现同步的方法来正确地访问共享资源.这些线程之间的关系是平等的,彼此之间并不存在任何依赖,它们各自竞争CPU资源,互不相让,并且还无条 ...
- java线程间通信:一个小Demo完全搞懂
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...
- 说说Java线程间通信
序言 正文 [一] Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在 ...
- 说说 Java 线程间通信
序言 正文 一.Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在一个 ...
随机推荐
- HDU 5634 线段树
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5634 题意:给定一个长度为n的序列,有m次操作.操作有3种: 1 l,r :区间[l,r]的值变成ph ...
- ZYNQ的Linux Linaro系统镜像制作SD卡启动(仅使用mkfs部分,其他部分待看)
0. 概述 ZYNQ生成uboot的时候和正常的ARM设备不太一样,ZYNQ属于二次辅助启动uboot然后由uboot启动内核,大概意思就是 ZYNQ内部有一个机制,该机制不可修改,可以通过拨码开关控 ...
- shell 函数传递参数的几种方式
1.最近总结了 shell 中 function 的传递变量的几种方式 1.传递单个变量 2.传递数组变量 #!/bin/bash #trying to pass an variable. ...
- ARC102E - Stop. Otherwise... 组合计数
枚举 \(i\),然后可以把 \(j\) 和 \(i - j\) 绑定成一对.把一对看成一个整的元素,与别的没有被绑定的数一起来参与选择就可以了. 但是由于实际上一对中的数是可以二选一的,所以不妨令 ...
- hdu 3183 rmq+鸽巢原理
题目大意: 给你一个数字字符串序列,给你要求删掉的数字个数m,删掉m个数使的剩下的数字字符串的之最小.并输出这个数字: 基本思路; 这题解法有很多,贪心,rmq都可以,这里选择rmq,因为很久没有写r ...
- AGC016题解
呼我竟然真的去刷了016QwQ[本来以为就是个flag的233] 感觉AGC题目写起来都不是很麻烦但是确实动脑子qvq[比较适合训练我这种没脑子选手] 先扔个传送门:点我 A.Shrinking 题意 ...
- vuejs如何调试代码
基于webpack的配置调试 使用Vue-cli命令行工具初始化基于wabpack模板的项目的命令语法: npm install -g @vue/cli # 全局安装vue-cli,版本vue3.x ...
- springboot 加载jsp 刷新jsp ,刷新Controller (亲自尝试)
解决jsp加载成功.<dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId&g ...
- 第三周作业—N42-虚怀若谷
一.显示/etc/目录下,以非字母开头,后面跟了一个字母以及其它任意长度任意字符的文件或目录 ls /etc/[^[:alpha:]][[:alpha:]]* 二.复制/etc/目录下所有以p开头的 ...
- centos6安装完成之后必要的配置
centos6安装完成之后必要的配置 一配置yum源 [root@centos61 ~]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirro ...