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 ...
随机推荐
- 【转载】Atom 是一款各方面体验都很像 Sublime Text 的编辑器
转载:http://www.appinn.com/atom-editor/ Atom 是一款各方面体验都很像 Sublime Text 的编辑器,它由 Github 出品,目前免费. Atom 功能的 ...
- JavaScript函数的方法
在一个对象中绑定函数,称为这个对象的方法. 在JavaScript中,对象的定义是: var xiaoming = { name:'小明'; birth:1990; }; 但是,如果我们给xiaomi ...
- VSTO Project 客户端自动发送邮件
利用office vsto功能,抓取我们选择的任务,根据配置节,邮件发送内容,最终根据任务名称,任务开始结束时间,任务资源名称,发送邮件给任务资源. 这是我的VSTO界面. 配置我们发送邮件的服务器地 ...
- 课时89.CSS三大特性练习(理解)
给大家补充一点:通配符是不参与权重计算的,因为通配符的权重是0,而权重只计算id,类,标签,将来还有一种,到后面说. 练习1 直接选中和间接选中的,必然要听直接选中的. 练习2 直接选中一共有两个,直 ...
- Spring知识点总结(四)之SpringAOP基础 - 代理设计模式
1. 分析程序中存在的问题(高内聚,低耦合) 通过springIOC DI) 以及注解的使用,成功解决了在程序中层与层之间出现的耦合的问题,但是在很多地方仍然存在非该层应该实现的 ...
- oracle中lock和latch的用途
本文向各位阐述Oracle的Latch机制,Latch,用金山词霸翻译是门插栓,闭锁,专业术语叫锁存器,我开始接触时就不大明白为什么不写Lock,不都是锁吗?只是翻译不同而以?研究过后才知道两者有很大 ...
- 一个关于 json ,加密,测试,集多功能为一体的在线工具
很多情况下我们会序列化json或者解析json,那么要解析json也许使用json实体类会好很多,或者你有时候需要压缩转义json的时候, 有一个网站真的是非常好用,里面什么都有......是真的啥都 ...
- 导入项目后,js文件报错解决方法
导入项目后,发现 js文件报错,但是js文件是从官网下载的.解决办法: 选中报错的js文件, 右键选择 MyEclipse-->Exclude From Validation : 然后继续右键执 ...
- Linux运维工作中需要掌握的知识
说到工具,在行外可以说是技能,在行内我们一般称为工具,就是运维必须要掌握的工具.我就大概列出这几方面,这样入门就基本没问题了.linux系统如果是学习可以选用redhat或centos,特别是cent ...
- 【linux下dhcp服务的简单搭建及优化部署】
dhcp server: 1::vim /etc/sysconfig/network-scripts/ifcfg-scfg:配置 server的 static IP: 2:vim /etc/dhcpd ...