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并发基础--线程通信的更多相关文章

  1. Java 并发基础——线程安全性

    当线程安全:多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么久称这个类是线程安全的. 在线程 ...

  2. Java并发基础--线程安全

    一.线程安全 1.线程安全的概念 线程安全:某个类被单个线程,或者多个线程同时访问,所表现出来的行为是一致,则可以说这个类是线程安全的. 2.什么情况下会出现线程安全问题 在单线程中不会出现线程安全问 ...

  3. 【Java并发】线程通信

    一.概述 1.1 什么是多线程之间通讯? 1.2 案例 代码实现 解决线程安全问题 二.等待通知机制 2.1 示例 2.2 wait与sleep区别 三.Lock锁 3.1 概述 3.2 等待/通知机 ...

  4. java并发基础(五)--- 线程池的使用

    第8章介绍的是线程池的使用,直接进入正题. 一.线程饥饿死锁和饱和策略 1.线程饥饿死锁 在线程池中,如果任务依赖其他任务,那么可能产生死锁.举个极端的例子,在单线程的Executor中,如果一个任务 ...

  5. java并发编程 线程基础

    java并发编程 线程基础 1. java中的多线程 java是天生多线程的,可以通过启动一个main方法,查看main方法启动的同时有多少线程同时启动 public class OnlyMain { ...

  6. Java 并发基础

    Java 并发基础 标签 : Java基础 线程简述 线程是进程的执行部分,用来完成一定的任务; 线程拥有自己的堆栈,程序计数器和自己的局部变量,但不拥有系统资源, 他与其他线程共享父进程的共享资源及 ...

  7. Java并发基础概念

    Java并发基础概念 线程和进程 线程和进程都能实现并发,在java编程领域,线程是实现并发的主要方式 每个进程都有独立的运行环境,内存空间.进程的通信需要通过,pipline或者socket 线程共 ...

  8. java并发基础及原理

    java并发基础知识导图   一 java线程用法 1.1 线程使用方式 1.1.1 继承Thread类 继承Thread类的方式,无返回值,且由于java不支持多继承,继承Thread类后,无法再继 ...

  9. 【搞定 Java 并发面试】面试最常问的 Java 并发基础常见面试题总结!

    本文为 SnailClimb 的原创,目前已经收录自我开源的 JavaGuide 中(61.5 k Star![Java学习+面试指南] 一份涵盖大部分Java程序员所需要掌握的核心知识.欢迎 Sta ...

随机推荐

  1. 【luogu P3385 负环】 模板

    题目链接:https://www.luogu.org/problemnew/show/P3385 SPFA判负环. 这个题必须卡一卡才过得去. 按理说对于一个负环点应当是入队 > n次. 但是这 ...

  2. 【luogu P3369 【模板】普通平衡树(Treap/SBT)】 模板 Scapegoat Tree

    #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> ...

  3. Mapreduce-Partition分析(转)

    http://blog.oddfoo.net/2011/04/17/mapreduce-partition%E5%88%86%E6%9E%90-2/ Partition所处的位置 Partition位 ...

  4. some small knowledge

    cookie 增查 <!--1.语义化标签的作用--> <!--1.1 从开发角度考虑是提高代码的可读性可维护性--> <!--1.2 网站的发布者:seo 搜索引擎优化 ...

  5. Java虚拟机垃圾回收(三): 7种垃圾收集器(转载)

    1.垃圾收集器概述 垃圾收集器是垃圾回收算法(标记-清除算法.复制算法.标记-整理算法.火车算法)的具体实现,不同商家.不同版本的JVM所提供的垃圾收集器可能会有很在差别,本文主要介绍HotSpot虚 ...

  6. 菜鸟笔记 -- Chapter 6 面向对象

    在Java语言中经常被提到的两个词汇是类与对象,实质上可以将类看作是对象的载体,它定义了对象所具有的功能.学习Java语言必须要掌握类与对象,这样可以从深层次去理解Java这种面向对象语言的开发理念, ...

  7. mysql快速导入导出数据

    --导入 select * from inhos_genoperation(表名) where UPLOAD_ORG_CODE='***' into outfile '/tmp/inhos_genop ...

  8. socket手写一个简单的web服务端

    直接进入正题吧,下面的代码都是我在pycharm中写好,再粘贴上来的 import socket server = socket.socket() server.bind(('127.0.0.1', ...

  9. ABAP术语-BW (Business Information Warehouse)

    BW (Business Information Warehouse) 原文:http://www.cnblogs.com/qiangsheng/archive/2008/01/14/1037761. ...

  10. python 面向对象类与类之间的关系

    主要内容: 1. 依赖关系 2. 关联关系, 组合关系, 聚合关系 3. 继承关系 4. 类中的特殊成员 引子 大千世界, 万物之间皆有规则和规律,我们的类和对象是对大千世界中的所有事物进行归类. 那 ...