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. 在VS2010 中使用subversion 进行代码的分支与合并

    在实际开发总,遇到了这种情况: 开发版本1,开发版本2 ,更新产品时要求1在前,2在后. 但是因为时间要求,必须2个版本同时开发.这时就想到了在svn的版本分支合并. 创建分支之前,首先把当前版本代码 ...

  2. 优雅的QSignleton (三) 通过属性器实现Singleton

    接下来介绍,不通过继承的方式实现单例模式.大家都出去嗨了,而我却在家码代码... 代码如下: MonoSingletonProperty.cs namespace QFramework.Example ...

  3. ETO的公开赛T5《猎杀蓝色空间号》题解

    这道题别看题面这么长,其实题意很简单 就是让你求从起点开始的最长合法区间 合法的要求有两个:兜圈子和直飞 且这两个条件相互独立 (也就是说兜圈子的末尾不会对下面可能出现的直飞造成影响) 举个例子: 1 ...

  4. linux 2.6升级Python2.7 ./configure 报错问题

    升级2.7.3使用命令./configure --prefix=/usr/local/python2.7.3时,出现以下错误:checking build system type... x86_64- ...

  5. Ubuntu下安装Docker CE

    官网配置步骤:https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-docker-ce-1 安装Docker社区版仓库 Upd ...

  6. python中的数据类型之元组和字典

    一.元组:俗称不可变的列表,又被称为只读列表.元组用小括号括起来,里面可以放任何数据类型的数据,查询可以,循环也可以,切片也可以,但就是不能修改. 注意:如果元组中只有一个元素,一定要加一个逗号,否则 ...

  7. ctf题目writeup(9)

    继续刷题,找到一个 什么 蓝鲸安全的ctf平台 地址:http://whalectf.xin/challenges (话说这些ctf平台长得好像) 1. 放到converter试一下: 在用十六进制转 ...

  8. 华为机试 求int型数据在内存中存储时1的个数

    题目描述 输入一个int型的正整数,计算出该int型数据在内存中存储时1的个数. 输入描述: 输入一个整数(int类型) 输出描述: 这个数转换成2进制后,输出1的个数 输入 5 输出 2 普通运算方 ...

  9. uva 509 RAID!(磁盘数据)

    来自 https://blog.csdn.net/su_cicada/article/details/80085318 习题4-7 RAID技术(RAID!, ACM/ICPC World Final ...

  10. 02---Nginx

    Nginx .caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: ...