java多线程编程核心技术——第三章

第一节等待/通知机制


    

本小节中使用了sleep()与while(true)实现了多线程间的通信。

原理:有一公共类,内有List集合,并提供add()方法向其中添加元素。

线程A开启后每一秒钟调用add()方法

线程B开启后一直循环查询List的大小,当超过定值时抛出异常终止线程。

弊端:线程B不停的while语句轮询机制检查某一条件,浪费CPU。

若轮询时间小,CPU资源更加浪费,若轮询时间过大,则可能无法得到预想的值。

 

java多线程编程核心技术——第三章

 

  方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法用来将当前线程置入“预执行队列”中,并且在wait()所在的代码行处停止执行,直到接到通知或被中断为止。

在调用wait()之前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步代码块中执行wait()方法。在执行wait()方法后,当前线程释放锁。在从wait()返回前,线程与其他线程竞争重新获得锁。若在调用wait()时没有持有适当的锁,则会抛出IllegalMonitorStateException,他是RuntimeException的一个子类,因此不需要try/catch进行捕捉异常。

  方法notify()也要在同步方法或同步代码块中调用,即在调用前,线程也必须获得该对象的对象级别锁。如果调用notify()时没有持有适当的锁,也会抛出IllegalMonitorStateException异常。该方法用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随机挑选出一个呈wait状态的线程,对其发出通知notify,并使它等待获取该对象的对象锁。需要说明的是,在执行notify()方法后,当前线程不会马上释放该对象锁,呈wait状态的线程也并不能马上获取该对象锁,要等到执行notify()方法的线程将程序执行完毕,也就是退出synchronized代码块后,当前线程才会释放锁,而呈wait状态所在的线程才能获取该对象锁。当第一个获得了该对象锁的wait线程运行完毕以后,它会释放掉该对象锁,此时如果该对象没有再次使用notify语句,则即便该对象以及空闲,其他wait状态等待的线程由于没有得到该对象的通知,还会继续阻塞在wait状态,直到这个对象发出一个notify或notifyAll。

  简而言之:

wait()使线程停止运行,notify()使停止的线程继续运行。

wait()与notify()都需要对象级别的锁存在才能调用。

wait()执行后,当前线程立即释放对象锁,notify()执行后,需等待同步代码执行完毕才能够释放对象锁,并唤醒其他线程。

  :wait()与notify()都是Object的方法,在“等待”跟“通知”时,均是由锁对象自己来调用wait()与notify()的。

  wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,知道被再次唤醒。

  notify()方法可以随机唤醒等待队列等待同一共享资源的“一个”线程,并使该线程退出等待队列,进入可运行状态,仅通知“一个”线程。

  notifyAll()可以使所有正在等待队列中等待统一资源的“全部”线程从等待状态退出,进入可运行状态。此时,优先级最高的那个线程最先执行,但也有可能是随机执行,这取决于JVM实现。

java多线程编程核心技术——第三章

 

  线程的几个状态:

 

  1)新创建一个线程对象后,再调用它的start()方法,系统会为此线程分配CPU资源,使其处于Runnable(可运行)状态,这是一个准备运行的阶段,如果线程抢占到CPU资源,此时线程处于Running(运行)状态。

  2)Runnable状态和Running状态可以互相切换,因为有可能线程运行一段时间后,有其他高优先级的线程抢占了CPU资源,这是线程就从Running状态转化为Runnable状态。

 

    线程进入Runnable状态大体分为以下5种情况:

调用sleep()方法后经过的时间超过了指定的休眠时间。

线程调用的阻塞IO已经返回,阻塞方法执行完毕。

线程成功获得了试图同步的监视器。

线程正在等待某个通知,其他线程发出了通知。

处于挂起状态的线程调用了resume恢复方法。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwgzp.html