java线程等待/通知机制及中断
来源:互联网 发布:厦门第二世界网络 编辑:程序博客网 时间:2024/05/19 22:51
一、等待/通知机制
在线程交互中经常需要对其进行一些控制,希望人为地能够让线程按理想路线发展,在满足某条件时进行执行操作而发生变化时,停止等待。
1、 使用sleep
在 if ( ) { } else { } 中使用sleep 对线程进行停止等待一段时间。 弊端:正常情况下 无法客观预知需要等待的时间,在刻意睡眠一段时间后 很可能发现 依旧不适合由此线程执行之后的操作,或者睡眠过久。
2、 使用 while + sleep 循环判断条件 使其睡眠 弊端:虽然能加快判断条件的变化,但依旧难以确保及时性,会造成无端浪费。
3、wait +notify :在某条件发生情况下,线程A调用对象O 的wait() 方法进入等待状态,当线程B调用对象O的notify() 或者notifyAll()方法后,线程A会接受通知,从其wait方法返回,执行后续操作。
java.lang.Obejct :
notify() 通知一个在对象上等待的线程,使其从wait方法返回(前提是该线程获取到对象的锁)
notifyAll() 通知所有等待在该对象上的线程 (注意,notify等通知时 不会释放当前对象锁)
wait() 调用该方法的线程进入Waiting状态,只有被中断或者由其他线程通知唤醒才能继续(wait会导致线程释放对象锁)
wait(long) 超时等待一段时间,等待xx毫秒,若没有收到通知 则超时返回
wait(long,int)超时精确到纳秒
例:
import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.TimeUnit;public class WaitAndNotify {static boolean flag=true;static Object lock =new Object();public static void main(String[] args) throws InterruptedException {Thread waitThread=new Thread(new Wait(),"waitThread");waitThread.start();TimeUnit.SECONDS.sleep(2);Thread notifyThread=new Thread(new Notify(),"notifyThread");notifyThread.start();}static class Wait implements Runnable{@Overridepublic void run() {synchronized (lock) {//同步代码块while (flag) {try {System.out.println(Thread.currentThread().getName()+" flag=true. wait@"+new SimpleDateFormat("HH:mm:ss").format(new Date()));lock.wait();<span style="white-space:pre"></span>System.out.println("啊啊?");} catch (InterruptedException e) {e.printStackTrace();}}//跳出while时System.out.println(Thread.currentThread().getName()+" flag=false. wait@"+new SimpleDateFormat("HH:mm:ss").format(new Date()));}} }static class Notify implements Runnable{@Overridepublic void run() {synchronized (lock) {//获取lock对象锁,然后通知唤醒System.out.println(Thread.currentThread().getName()+" hold lock. notify@"+new SimpleDateFormat("HH:mm:ss").format(new Date()));lock.notifyAll();flag=false;try {Thread.sleep(3000);//notify之后线程睡眠3秒,验证Wait类不能马上输出“啊啊?”} catch (InterruptedException e) {e.printStackTrace();}} //同步代码块结束后 释放锁synchronized (lock) {//再次加锁System.out.println(Thread.currentThread().getName()+" hold lock again. @"+new SimpleDateFormat("HH:mm:ss").format(new Date()));try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}}}}运行结果:(注:在notifyThread里的两个同步代码块之间 可能会发生lock被Wait获取 而使输出结果的第三、四行互换)
waitThread flag=true. wait@16:00:44notifyThread hold lock. notify@16:00:46notifyThread hold lock again. @16:00:49啊啊?waitThread flag=false. wait@16:00:51
waitThread 获取到lock对象锁,之后调用wait()方法进入等待队列,而同时会释放掉对象锁,状态为Waiting。 notifyThread获取lock对象锁后调用notify()方法通知一个等待线程(本例中仅一个等待线程),将其移到同步队列,然后继续执行自己的代码,当释放掉lock对象锁后,waitThread线程才有可能重新获取lock并执行先前未完成的代码。 借助《Java并发编程的艺术》中一图:
注意:
1)wait() notify() notifyAll() 等使用时 需要先对调用的对象加锁获取。
2)wait()之后 线程由Running转变为Waiting 将会把当前线程防止到对象的等待队列。
3)并不是一旦使用notify() notifyAll() 就能实现线程执行wait()方法之后的代码段,需要等发出notify()的线程先释放对象锁然后 等待线程重新获得lock锁 才可以执行原wait()之后的操作!4)notify()方法将等待队列中的一个等待线程从其中移到同步队列中,而notifyAll()方法则是唤醒等待队列中的所有线程,全部移到同步队列,将Waiting改为Blocked
等待方:①.获取对象锁 ②.若条件不满足则调用对象wait(),被通知后要重新判断条件(可能会伪唤醒)③.满足条件后执行后续操作
通知方:①.获取对象锁 ②.改变条件 ③.通知等待的线程
二、中断及join()
interrupt()只是改变中断状态而已. interrupt()不会中断一个正在运行的线程。这一方法实际上完成的是,给受阻塞的线程抛出一个中断信号,这样受阻线程就得以退出阻塞的状态。如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,它将接收到一个中断异常(InterruptedException),从而提早地终结被阻塞状态。
join() 含义:若线程A执行某thread线程的join(),那么当前线程A等待thread线程终止之后才能从join()返回
例: 每个线程调用前一个线程的join() 按顺序结束操作。
import java.util.concurrent.TimeUnit;public class Test2 {public static void main(String[] args) throws InterruptedException {Thread[] myThreads =new Thread[5];Thread previous=Thread.currentThread();for(int i=0;i<5;i++){myThreads[i]=new Thread(new Runner(previous),i+1+" Thread");myThreads[i].start();previous=myThreads[i];}//TimeUnit.SECONDS.sleep(3);//main sleep 3s//myThreads[3].interrupt();TimeUnit.SECONDS.sleep(3);//main sleep 3sSystem.out.println(Thread.currentThread().getName()+" terminate");} static class Runner implements Runnable{ private Thread aThread; public Runner( Thread aThread) {this.aThread=aThread;}@Overridepublic void run() {try {aThread.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+" terminate");} }}运行结果:
main terminate1 Thread terminate2 Thread terminate3 Thread terminate4 Thread terminate5 Thread terminate
再结束mian 1 2 3 注:由于线程一直运行,在报错的同时,已经在输出4的语句
java.lang.InterruptedException4 Thread terminateat java.lang.Object.wait(Native Method)at java.lang.Thread.join(Thread.java:1249)at java.lang.Thread.join(Thread.java:1323)at Test2$Runner.run(Test2.java:25)at java.lang.Thread.run(Thread.java:745)5 Thread terminatemain terminate1 Thread terminate2 Thread terminate3 Thread terminate
- java线程等待/通知机制及中断
- java线程同步的等待通知机制
- java线程第四课:线程的等待通知机制
- java线程之间的通信(等待/通知机制)
- Java线程之间的通信-等待/通知机制
- java多线程之线程间通信:等待/通知机制
- java线程之间的通信(等待/通知机制)
- java线程之间的通信(等待/通知机制)
- java线程之间的通信(等待/通知机制)
- Java的等待通知机制
- java线程等待与通知
- Java多线程之线程间通信--等待(wait)/通知(notify)机制,等待/通知之交叉备份实例
- java 线程中断机制
- java线程中断机制
- 多线程中的线程间通信及等待/通知机制的两种实现方式
- Java等待/通知机制:生产者-消费者问题
- java多线程的等待和通知机制
- java并发(等待/通知机制)
- CodeForces 550B Preparing Olympiad 简单DFS
- 2016-10-30
- 在Ubuntu下开发React-Native之填坑记(一)
- DrawerLayout must be measured with MeasureSpec.EXACTLY error
- CentOS7下编译安装ffmpeg3.1.5
- java线程等待/通知机制及中断
- poj 3984
- 关于"\r","\n","\r\n"区别的实践
- js 使元素获取或失去焦点
- AS签名打包(一)Build打包
- 文件操作
- Mac下安装HBase及详解
- iOS中 addChildViewControllers 调整tableView位置
- Centos 6.5 关闭防火墙的步骤