Java并发基础--线程通信
java中实现线程通信的四种方式
1.synchronized同步
多个线程之间可以借助synchronized关键字来进行间接通信,本质上是通过共享对象进行通信。如下:
public class SynDemo {
public synchronized void print1(){
System.out.println(Thread.currentThread().getName()+"执行......");
}
public synchronized void print2(){
System.out.println(Thread.currentThread().getName()+"执行......");
}
public static void main(String[] args) {
SynDemo synDemo = new SynDemo();//共享对象
new Thread(new Mythread1(synDemo)).start();
new Thread(new Mythread0(synDemo)).start();
}
}
class Mythread1 implements Runnable{
private SynDemo syn;
Mythread1(SynDemo syn){
this.syn =syn;
}
@Override
public void run() {
syn.print1();
}
}
class Mythread0 implements Runnable{
private SynDemo syn;
Mythread0(SynDemo syn){
this.syn =syn;
}
@Override
public void run() {
syn.print2();
}
}
结果输出:
Thread-0执行......
Thread-1执行......
2.while轮询的方式
一个线程修改共享对象的某个属性,另外一个线程不断的轮训查看共享对象的这个属性是否发生符合条件的变化。本质上同样是借助共享对象进行通信,通过不断轮训,判断共享对象的某个属性(CPU的cache被刷新后,在另外线程可以看其他线程中对象的属性发生变化)符合条件后打破循环。示例如下:
public class WhileDemo {
private List list = new ArrayList();
public void addList(){
System.out.println("list+1");
list.add(1);
}
public int listSize(){
return list.size();
}
public static void main(String[] args) {
WhileDemo WhileDemo = new WhileDemo();//共享对象
new Thread(new Mythread3(WhileDemo)).start();
new Thread(new Mythread4(WhileDemo)).start();
}
}
class Mythread3 implements Runnable{
private WhileDemo wd;
Mythread3(WhileDemo wd){
this.wd =wd;
}
@Override
public void run() {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
wd.addList();
wd.addList();
}
}
class Mythread4 implements Runnable{
private WhileDemo wd;
Mythread4(WhileDemo wd){
this.wd =wd;
}
@Override
public void run() {
try {
while(true){
if(wd.listSize()==2){
System.out.println(Thread.currentThread().getName()+"达到要求,退出");
break;
}
//未达到要求
System.out.println("暂时不满足要求,继续运行");
Thread.sleep(100);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果输出:
暂时不满足要求,继续运行
暂时不满足要求,继续运行
暂时不满足要求,继续运行
Thread-0 list+1
Thread-0 list+1
Thread-1达到要求,退出
3.waite/notify通信
在Java中,可以通过配合调用Object对象的wait()方法和notify()方法或notifyAll()方法来实现线程间的通信。在线程中调用wait()方法后,将阻塞等待其他线程的通知(其他线程调用notify()方法或notifyAll()方法),当其他线程中调用notify()方法或notifyAll()方法后,被阻塞等待的线程将被唤醒。示例如下:
public class WNDemo {
private List list = new ArrayList();
public void addList(){
System.out.println(Thread.currentThread().getName()+" list+1");
list.add(1);
}
public int listSize(){
return list.size();
}
public static void main(String[] args) {
WNDemo WNDemo = new WNDemo();//共享对象
new Thread(new Mythread5(WNDemo)).start();
new Thread(new Mythread6(WNDemo)).start();
}
}
class Mythread5 implements Runnable{
private WNDemo wd;
Mythread5(WNDemo wd){
this.wd =wd;
}
@Override
public void run() {
try {
synchronized (wd) {
while (wd.listSize()!=5) {
System.out.println(Thread.currentThread().getName()+" list大小不满足要求,进入wait状态,等待唤醒");
wd.wait();
}
System.out.println(Thread.currentThread().getName()+" list大小满足要求,执行结束");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Mythread6 implements Runnable{
private WNDemo wd;
Mythread6(WNDemo wd){
this.wd =wd;
}
@Override
public void run() {
try {
synchronized (wd) {
for(int i=0;i<5;i++){
wd.addList();
}
wd.notify();//唤醒处于等待状态wd的线程
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果输出:
Thread-0 list大小不满足要求,进入wait状态,等待唤醒
Thread-1 list+1
Thread-1 list+1
Thread-1 list+1
Thread-1 list+1
Thread-1 list+1
Thread-0 list大小满足要求,执行结束
注意:
- wait()与 notify()/notifyAll()方法必须在同步代码块中使用。
- 当线程执行wait()时,会把当前的锁释放,然后让出CPU,进入等待状态。
- 当执行notify/notifyAll方法时,不会立即释放锁。会唤醒一个处于等待该对象锁的线程,然后继续往下执行,直到执行完退出对象锁锁住的区域(synchronized修饰的代码块)后再释放锁。
- notifyAll使所有原来在该对象上wait的线程统统退出wait的状态,变成等待获取该对象锁的状态,一旦当等待的对象锁被释放,这些被唤醒的线程进行竞争,获取锁的线程继续执行,其他的继续等待锁的释放。
- wait(long),如果在指定时间了未被唤醒,则自动进入竞争锁状态。也可能是在指定时间内被其他线程唤醒。
4.管道通信
管道流主要用来实现两个线程间二进制数据的流通。示例如下:
public class PipeDemo {
public static void main(String[] args) {
PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream();
try {
pis.connect(pos);//连接管道输入流和输出流
} catch (IOException e) {
e.printStackTrace();
}
new Thread(new MyThread1(pis)).start();
new Thread(new Mythread2(pos)).start();
}
}
class MyThread1 implements Runnable{
private PipedInputStream pis;
public MyThread1(PipedInputStream pis){
this.pis = pis;
}
@Override
public void run() {
while(true){//不断轮训管道输入流中是否有字节数据
try {
int count = pis.available();
if(count>0){
System.out.println("开始从管道流中读取数据");
System.out.println(pis.read());//读取一个字节
System.out.println("从管道流中读取数据完毕");
break;
}
System.out.println("管道流中暂时还没有数据");
//如果输入流中暂时没有数据
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class Mythread2 implements Runnable{
private PipedOutputStream pos;
public Mythread2(PipedOutputStream pos){
this.pos = pos;
}
@Override
public void run() {
try {
Thread.sleep(500);
System.out.println("开始往管道流写入数据");
pos.write(96);//写入一个字节进管道输出流
System.out.println("管道流中写入数据完毕");
} catch (Exception e) {
e.printStackTrace();
}
}
}
结果输出:
管道流中暂时还没有数据
开始往管道流写入数据
管道流中写入数据完毕
开始从管道流中读取数据
96
从管道流中读取数据完毕
Java并发基础--线程通信的更多相关文章
- Java 并发基础——线程安全性
当线程安全:多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么久称这个类是线程安全的. 在线程 ...
- Java并发基础--线程安全
一.线程安全 1.线程安全的概念 线程安全:某个类被单个线程,或者多个线程同时访问,所表现出来的行为是一致,则可以说这个类是线程安全的. 2.什么情况下会出现线程安全问题 在单线程中不会出现线程安全问 ...
- 【Java并发】线程通信
一.概述 1.1 什么是多线程之间通讯? 1.2 案例 代码实现 解决线程安全问题 二.等待通知机制 2.1 示例 2.2 wait与sleep区别 三.Lock锁 3.1 概述 3.2 等待/通知机 ...
- java并发基础(五)--- 线程池的使用
第8章介绍的是线程池的使用,直接进入正题. 一.线程饥饿死锁和饱和策略 1.线程饥饿死锁 在线程池中,如果任务依赖其他任务,那么可能产生死锁.举个极端的例子,在单线程的Executor中,如果一个任务 ...
- java并发编程 线程基础
java并发编程 线程基础 1. java中的多线程 java是天生多线程的,可以通过启动一个main方法,查看main方法启动的同时有多少线程同时启动 public class OnlyMain { ...
- Java 并发基础
Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...
- Java并发基础概念
Java并发基础概念 线程和进程 线程和进程都能实现并发,在java编程领域,线程是实现并发的主要方式 每个进程都有独立的运行环境,内存空间.进程的通信需要通过,pipline或者socket 线程共 ...
- java并发基础及原理
java并发基础知识导图 一 java线程用法 1.1 线程使用方式 1.1.1 继承Thread类 继承Thread类的方式,无返回值,且由于java不支持多继承,继承Thread类后,无法再继 ...
- 【搞定 Java 并发面试】面试最常问的 Java 并发基础常见面试题总结!
本文为 SnailClimb 的原创,目前已经收录自我开源的 JavaGuide 中(61.5 k Star![Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.欢迎 Sta ...
随机推荐
- 【洛谷P1367】蚂蚁
蚂蚁 [题目描述] 在一根无限长的木棍上,用n只蚂蚁,每只蚂蚁有一个初始位置和初始朝向,蚂蚁们以每秒一个单位的速度向前移动,当两只蚂蚁相遇时,它们会掉头(掉头时间忽略不计).现给出每只蚂蚁的初始位置和 ...
- 【luogu P3371 单源最短路径】 模板 dij + heap
题目链接:https://www.luogu.org/problemnew/show/P3371#sub 堆优化迪杰斯特拉,留着以后复习用 #include <iostream> #inc ...
- 【题解】洛谷P1350 车的放置(矩阵公式推导)
洛谷P1350:https://www.luogu.org/problemnew/show/P1350 思路 把矩阵分为上下两块N与M 放在N中的有i辆车 则放在M中有k-i辆车 N的长为a 宽为 ...
- Python 学习笔记(六)Python第一个程序
Python 语句 赋值语句 1.将3对象赋值给了变量a 2.将3,4赋值给了变量a,b >>> a = 3 >>> a ,b = 3,4 >>> ...
- [Windows]ping itsafe&环境变量
(1)when you ping a computer from itsafe,the ping command should return the local IP address. (2)wind ...
- springboot+mybatisplus 测试代码生成
测试springboot + mybatisplus 实现代码生成 使用默认的模板引擎 pom.xml文件 <?xml version="1.0" encoding=&q ...
- 移动设备HTML5页面布局
在HTML5标准添加的新元素中,用于常见页面结 构的包括header footer footer nav aside aside article section hgroup . 下面简单介绍一下这个 ...
- Django模板简介
在settings.py中有个TEMPLATES的设置,其中BACKEND用来配置Django模板引擎, DIRS 定义了一个目录列表,模板引擎按列表顺序搜索这些目录以查找模板源文件 一般我们都会把模 ...
- 1486: [HNOI2009]最小圈
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 3129 Solved: 1543[Submit][Status][Discuss] Descripti ...
- C/C++获取CPU等硬件信息&&屏幕截图
打算练习Socket的时候用用,最近有点小事情,没时间继续完善,先把写的这些代码贴上来,有空了再完善一下. HardwareInfo.h #include <stdio.h> #inclu ...