




全文预览已结束
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
基础篇(四)wait(),notify()/notityAll()方法关于这两个方法,有很多的内容需要说明.在下面的说明中可能会有很多地方不能一下子明白,但在看完本节后,即使不能完全明白,你也一定要回过头来记住下面的两句话:wait(),notify()/notityAll()方法是普通对象的方法(Object超类中实现),而不是线程对象的方法wait(),notify()/notityAll()方法只能在同步方法中调用线程的互斥控制多个线程同时操作某一对象时,一个线程对该对象的操作可能会改变其状态,而该状态会影响另一线程对该对象的真正结果.这个例子我们在太多的文档中可以看到,就象两个操售票员同时售出同一张票一样.线程A 线程B1.线程A在数据库中查询存票,发现票C可以卖出2.线程A接受用户订票请求,准备出票.3. 这时切换到了线程B执行4. 线程B在数据库中查询存票,发现票C可以卖出 5. 线程B将票卖了出去 6.切换到线程A执行,线程A卖了一张已经卖出的票所以需要一种机制来管理这类问题的发生,当某个线程正在执行一个不可分割的部分时,其它线程不能不能同时执行这一部分.象这种控制某一时刻只能有一个线程执行某个执行单元的机制就叫互斥控制或共享互斥(mutual exclusion)在JAVA中,用synchronized关键字来实现互斥控制(暂时这样认为,JDK1.5已经发展了新的机制)synchornized关键字把一个单元声明为synchronized,就可以让在同一时间只有一个线程操作该方法.有人说synchornized就是一把锁,事实上它确实存在锁,但是是谁的锁,锁谁,这是一个非常复杂的问题.每个对象只有一把监视锁(monitor lock),一次只能被一个线程获取.当一个线程获取了这一个锁后,其它线程就只能等待这个线程释放锁才能再获取.那么synchronized关键字到底锁什么?得到了谁的锁?对于同步块,synchronized获取的是参数中的对象锁:synchronized(obj)/.线程执行到这里时,首先要获取obj这个实例的锁,如果没有获取到线程只能等待.如果多个线程执行到这里,只能有一个线程获取obj的锁,然后执行中的语句,所以,obj对象的作用范围不同,控制程序不同.假如:public void test()Object o = new Object();synchronized(obj)/.这段程序控制不了任何,多个线程之间执行到Object o = new Object();时会各自产生一个对象然后获取这个对象有监视锁,各自皆大欢喜地执行.而如果是类的属性:class TestObject o = new Object();public void test()synchronized(o)/.所有执行到Test实例的synchronized(o)的线程,只有一个线程可以获取到监视锁.有时我们会这样:public void test()synchronized(this)/.那么所有执行Test实例的线程只能有一个线程执行.而synchornized(o)和synchronized(this)的范围是不同的,因为执行到Test实例的synchornized(o)的线程等待时,其它线程可以执行Test实例的synchronized(o1)部分,但多个线程同时只有一个可以执行Test实例的synchornized(this).而对于 synchronized(Test.class)/.这样的同步块而言,所有调用Test多个实例的线程赐教只能有一个线程可以执行.synchronized方法如果一个方法声明为synchronized的,则等同于把在为个方法上调用synchronized(this).如果一个静态方法被声明为synchronized,则等同于把在为个方法上调用synchronized(类.class).现在进入wait方法和notify/notifyAll方法.这两个(或叫三个)方法都是Object对象的方法,而不是线程对象的方法.如同锁一样,它们是在线程中调用某一对象上执行的.class Testpublic synchronized void test()/获取条件,int x 要求大于100;if(x 100)wait();这里为了说明方法没有加在trycatch()中,如果没有明确在哪个对象上调用wait()方法,则为this.wait();假如:Test t = new Test();现在有两个线程都执行到t.test();方法.其中线程A获取了t的对象锁,进入test()方法内.这时x小于100,所以线程A进入等待.当一个线程调用了wait方法后,这个线程就进入了这个对象的休息室(waitset),这是一个虚拟的对象,但JVM中一定存在这样的一个数据结构用来记录当前对象中有哪些程线程在等待.当一个线程进入等待时,它就会释放锁,让其它线程来获取这个锁.所以线程B有机会获得了线程A释放的锁,进入test()方法,如果这时x还是小于100,线程B也进入了t的休息室.这两个线程只能等待其它线程调用notityAll来唤醒.但是如果调用的是有参数的wait(time)方法,则线程A,B都会在休息室中等待这个时间后自动唤醒.为什么真正的应用都是用while(条件)而不用if(条件)在实际的编程中我们看到大量的例子都是用 while(x 100)wait();go();而不是用if,为什么呢?在多个线程同时执行时,if(x 100)是不安全的.因为如果线程A和线程B都在t的休息室中等待,这时另一个线程使x=100了,并调用notifyAll方法,线程A继续执行下面的go().而它执行完成后,x有可能又小于100,比如下面的程序中调用了-x,这时切换到线程B,线程B没有继续判断,直接执行go();就产生一个错误的条件,只有while才能保证线程B又继续检查一次.notify/notifyAll方法这两个方法都是把某个对象上休息区内的线程唤醒,notify只能唤醒一个,但究竟是哪一个不能确定,而notifyAll则唤醒这个对象上的休息室中所有的线程.一般有为了安全性,我们在绝对多数时候应该使用notifiAll(),除非你明确知道只唤醒其中的一个线程.那么是否是只要调用一个对象的wait()方法,当前线程就进入了这个对象的休息室呢?事实中,要调用一个对象的wait()方法,只有当前线程获取了这个对象的锁,换句话说一定要在这个对象的同步方法或以这个对象为参数的同步块中.class MyThread extends ThreadTest t = new Test();public void run()t.test();System.out.println(Thread say:Hello,World!);public class Test int x = 0;public void test()if(x=0)trywait();catch(Exception e)public static void main(String args) throws Exceptionnew MyThread().start();这个线程就不会进入t的wait方法而直接打印出Thread say:Hello,World!.而如果改成:public class Test int x = 0;public synchronized void test()if(x=0)trywait();catch(Exception e)public static void main(String args) throws Exceptionnew MyThread().start();
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论