Java基础教程:多线程基础(2)——线程间的通信
Java基础教程:多线程基础——线程间的通信
使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时还会使程序员对各线程任务在处理的过程中进行有效的把控与监督。
线程间的通信
思维导图
等待/通知机制
不使用等待/通知机制
我们可以使用使用sleep()与 whle(true) 死循环来实现多个线程间的通信。
虽然两个线程实现了通信,但是线程B必须不断的通过while语句轮训机制来检测某一个条件,这样会浪费CPU资源。
如果轮询间隔较小,更浪费时间间隔。如果轮训时间间隔较大,有可能会取不到想要得到的数据,所以需要一种机制来实现减少CPU的浪费。
等待/通知机制
等待/通知机制在生活中比比皆是,比如在就餐时
关于wait
wait的作用是使当前执行代码的线程进行等待,wait方法是Object类的方法,该方法用来将当前线程置入“预执行队列”中,并且在wait()所在的代码行处停止执行,直到接到通知或被中断为止。
在调用wait()之前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait方法。
在执行wait()方法后,当前线程释放锁。在从wait返回前,线程与其它线程竞争重新获得锁。
如果调用wait()时没有持有适当的锁,则会抛出IllegalMonitorStateException。
关于wait(long):
带一个参数的wait(long)方法的功能是等待某一时间内是否有线程对锁进行唤醒,如果超过这个时间则会自动唤醒。
关于notify
方法notify()也要在同步方法或同步块中调用,即在调用前,线程也必须获得该对象的对象级别锁。如果没有持有对象锁,则会抛出IllegalMonitorStateException。
该方法用来通知那些可能等待的该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选出其中一个呈wait状态的线程,对其发出通知notify,并使它等待获取该对象的对象锁。需要说明的是,在执行notify方法后,当前线程不会马上释放对象锁,呈wait状态的线程也不能马上获取该对象锁,要等待执行notify()方法的线程将程序执行完,也就是说退出synchronized代码块后,才能释放锁。
第一个获得该对象锁的wait线程运行完毕之后,它会释放掉该对象锁,此时如果该对象没有再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,还会继续阻塞在wait状态,直到这个对象发出一个notify或notifyall。
一句话总结:
wait使线程停止运行,而notify使停止的线程继续运行。
方法wait锁释放和notify锁不释放
当方法wait()被执行后,锁被自动释放;
执行完notify()方法,锁不会自动释放,必须要执行完notify()方法所在的同步synchronized代码块后才释放锁;
总结
- wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到被再次唤醒。
- notify()方法可以随机唤醒等待队列中等待同一个共享资源的一个线程,并使该线程退出等待队列,进入可运行状态,也就是notify()方法仅通知一个线程。
- nofityAll()方法可以使所有正在等待队列中等待同一个共享资源的全部线程从等待状态退出,进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,取决于JVM虚拟机的实现。
等待通知机制的实现
ThreadA——wait
public class MyThread1 implements Runnable { private Object key; public MyThread1(Object key) {
this.key =key;
} @Override
public void run() {
try {
synchronized (key)
{
System.out.println("开始 wait");
key.wait();
System.out.println("结束 wait");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
ThreadB——notify
public class MyThread2 implements Runnable { private Object key; public MyThread2(Object key) {
this.key = key;
} @Override
public void run() {
synchronized (key)
{
System.out.println("开始notify");
key.notify();
System.out.println("结束notify");
}
}
}
测试
public class Main {
public static void main(String[] args) {
String key = new String();
MyThread1 myThread1 = new MyThread1(key);
MyThread2 myThread2 = new MyThread2(key);
new Thread(myThread1).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(myThread2).start(); }
} /*
输出:
开始 wait
开始notify
结束notify
结束 wait */
方法Join实现同步
在很多情况下,主线程创建并启动子线程,如果子线程中要进行大量的耗时运算 ,主线程往往将早于子线程结束之前结束。这时,如果主线程想等待子线程执行完成之后再结束,比如子线程处理一个数据,主线程要取得这个数据的值,就要用到Join方法。方法Join的作用时等待线程对象销毁。
模拟场景
class MyThread extends Thread {
@Override
public void run() {
System.out.println(5);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
//Thread.sleep(???)
System.out.println("我想等thread对象执行完后再执行");
System.out.println("上面Sleep中的值应该写多少呢");
System.out.println("答案是不能确定");
}
} /*
输出:
我想等thread对象执行完后再执行
5
上面Sleep中的值应该写多少呢
答案是不能确定 */
用Join方法来解决
修改Main函数中的测试方法
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我想等thread对象执行完后再执行");
System.out.println("上面Sleep中的值应该写多少呢");
System.out.println("答案是不能确定");
}
}
说明:
方法Join的作用是使所属形成对象x正常执行完run()方法中的任务,而使当期线程Z处于无限期的阻塞,等待线程X销毁后再继续执行Z后面的代码。
方法Join具有使线程排队运行的作用,有些类似于同步的运行效果。
Join方法内部使用wait()来实现,会释放锁。
Java基础教程:多线程基础(2)——线程间的通信的更多相关文章
- Java核心知识点学习----多线程并发之线程间的通信,notify,wait
1.需求: 子线程循环10次,主线程循环100次,这样间隔循环50次. 2.实现: package com.amos.concurrent; /** * @ClassName: ThreadSynch ...
- iOS开发多线程篇 04 —线程间的通信
iOS开发多线程篇—线程间的通信 一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任 ...
- java多线程5:线程间的通信
在多线程系统中,彼此之间的通信协作非常重要,下面来聊聊线程间通信的几种方式. wait/notify 想像一个场景,A.B两个线程操作一个共享List对象,A对List进行add操作,B线程等待Lis ...
- Java并发编程的艺术(六)——线程间的通信
多条线程之间有时需要数据交互,下面介绍五种线程间数据交互的方式,他们的使用场景各有不同. 1. volatile.synchronized关键字 PS:关于volatile的详细介绍请移步至:Java ...
- iOS多线程编程之线程间的通信(转载)
一.简单说明 线程间通信:在1个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 线程间通信的体现 1个线程传递数据给另1个线程 在1个线程中执行完特定任务后,转到另1个线程继续执行任务 ...
- Java基础教程——多线程:创建线程
多线程 进程 每一个应用程序在运行时,都会产生至少一个进程(process). 进程是操作系统进行"资源分配和调度"的独立单位. Windows系统的"任务管理器&quo ...
- java并发编程(十一)线程间的通信notify通知的遗漏
notify通知的遗漏很容易理解,即threadA还没开始wait的时候,threadB已经notify了,这样,threadB通知是没有任何响应的,当threadB退出synchronized代码块 ...
- Java多线程编程(6)--线程间通信(下)
因为本文的内容大部分是以生产者/消费者模式来进行讲解和举例的,所以在开始学习本文介绍的几种线程间的通信方式之前,我们先来熟悉一下生产者/消费者模式. 在实际的软件开发过程中,经常会碰到如下场景 ...
- java多线程详解(6)-线程间的通信wait及notify方法
Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New) ...
随机推荐
- How To Commit Just One Data Block Changes In Oracle Forms
You have an Oracle Form in which you have multiple data blocks and requirement is to commit just one ...
- Microsoft JET Database Engine(0x80004005)未指定错误的解决方法
今天在给一台新的电脑安装IIS,安装成功,建立虚目录后,运行一个已经在别的机器上的正确的asp文件,就是不成功,提示:Microsoft JET Database Engine (0x80004005 ...
- JAVA实现EXCEL公式专题(四)——字符串函数
直接上代码: /** * 项目名称: * 文件说明: ExCEL公式类型:字符串公式 * 主要特点: * 版本:1.0 * 制作人:刘晨曦 * 创建时间:2013-12-3 **/ package E ...
- Win2003 IIS 安装方法 图文教程
最近水一水 质量不高 见谅 一般大家先安装好win2003系统,图文教程 Win2003 服务器系统安装图文教程要通过控制面板来安装.具体做法为: 1. 进入“控制面板”. 2. 双击“添加或删除程序 ...
- iOS开发个人独立博客收集
如今国内技术博客站点有非常多,如CSDN,CNBlog,ITEye等.论坛的话主要是要cocachina. 这里是我收集的iOS开发个人独立博客,文章用搜索引擎比較难搜到,都是牛人: OneV's D ...
- 分析cocos2d-x的lua项目中的工具方法
在创建完cocos2d-x的lua项目后.打开项目的Resources中的extern.lua文件.里面有两个用于面向对象的方法.一个是用于克隆,一个是用于继承. 代码分析例如以下 --克隆一个对象 ...
- widget 常用UI控件介绍
一.单选框 单选框实例程序: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&q ...
- 如何将数据导入到hive中
可以通过多种方式将数据导入hive表 1.通过外部表导入 用户在hive上建external表,建表的同时指定hdfs路径,在数据拷贝到指定hdfs路径的同时,也同时完成数据插入external表. ...
- Windows Thin PC体验 & 语言包更改(win 7 included)
本作品由Man_华创作,采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可.基于http://www.cnblogs.com/manhua/上的作品创作. 简介: Window ...
- RF --系统关键字开发
需求: 接收一个目录路径,自动遍历目录下以及子目录下的所有批处理(.bat) 文件并执行. 首先在..\Python27\Lib\site-packages 目录下创建 CustomLibrary 目 ...