`
freesoftman
  • 浏览: 313954 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Object中的wait(), notify(), notifyAll()的自己一些看法

阅读更多

昨天下班, 我回来后。由于没有钥匙,于是先到一个待就业的学弟那里做了一下。

首先我们谈了一下最近的就业环境。

后来他就像我问了一个Java基础方面的问题。

 

Object对象中有那些方法?

呵呵,还别说,  对于这些基础知识本人还是很有信息的。

 

但是结果还是差强人意。少说了两个方法equals(), clone();

 

一说起clone(),前不久在公司写的一个native方法,还打算去重载clone()这个方法呢

这里, 给大家和我都留下一个研究的问题。

那就是hashCode这个方法到底有什么用途? 它在C层面是怎么实现的?

这个这次就不做详细的研究了。

 

好了, 废话有点多了。 呵呵!

在看API文档的时候,我们又谈到了wait与sleep的区别等等。其中,在与他谈论中, 我自己想到一个问题,感觉还是满有意思的。

 

问题是:为什么wait(), notify()要放在同步快中呢?

Java中每个对象VM都会给它分配一个锁资源。参考源代码,可以知道wait, notify都是native方法,也就是本地方法。这些方法主要的目的是提供不同线程间的一个通信问题!由于这个目的,才会出现这些方法的。也就是说这两个方法VM的多线程设计是密切相关的。

当你在一个方法加上synchronized或同步块的话,VM会对你做一些额外的编码工作。主要是两个点,一个是进入点,一个是出入点。进入口:需要根绝当前对象的锁对象状态做不同的动作。出入口:释放当前对象锁资源。所以方法的同步是比一般的方法所耗费的时间是更久一点的。主要在进入口与出入口这里的额外耗费时间。

下面我对这个问题做一个猜测,当然希望那位大牛能做一个全面的解释。我这里只是猜测! OK! Go.

 wait, notify这两个方法主要是因为线程的同步机制才引入的,可以这么说它们是与线程的实现机制是密切相关的。而这两个方法是native方法实现的(参考源代码),也就是说在底层它做了什么我们根本不知道。但是一定会于锁有关系,因为wait方法有这么一个特性:wait住的线程会释放对象锁!从这里我们可以肯定一点wait会进行对象锁的操作!

而线程是一个随机调度的,假设我们不把wait放入同步快中。我来假设线程的一种调用情况:现在有两个线程t1, t2。一个对象obj。当t1调用wait,而wait还没有执行完, t2获得了CPU的时间片,t2也调用了wait()。那么wait将变得不可操作,因为t1,t2可能同时操作了锁资源!这样就会出现问题!

我的结论是:放入同步快中,主要是为了让wait与notify具有线性安全! 有的人可能会问,那为什么不在该方法前加同步关键字呢?呵呵!这是不可以的,因为它们是native方法, native方法的调用与Java的一般方法是有区别的。具体你可以去看<深入Java虚拟机>!

 

好了,这次就写到这里了。  最近正在研究公司的虚拟机,  若我有更好的解释我会继续发文章的!

分享到:
评论
4 楼 freesoftman 2010-06-20  
是的, 从eclipse的调试过程,你可能很清楚的看出这点
3 楼 2022228 2010-05-11  
你要释放某个锁,必须首先是获得了这个锁。所以必须写在同步快中。

同步快就是去获得某个锁
2 楼 freesoftman 2010-02-22  
呵呵,OK
很高兴看到你的回复。

最近正好打算研究kvm的多线程,就探讨一下吧

首先,我们都知道JVM会给每一个对象都分配唯一的一把锁。这把锁是在对象中的。

据我所知,不光是对象有锁,类也是有锁的。比如某个类有个静态的同步方法
public static synchronized void a() {
...
}

如果某个线程调用了该方法,那么这个线程就占用了这个类的锁。

所以个人认为JVM会给每个synchronized关键字都配上一个唯一的一把锁。
如果synchronized关键字是在方法定义的前边,那么就存在两种方式:一种为对象锁,另一种为类锁。我们姑且不管锁的形式是怎么样的,但是对象锁肯定与你创建的对象有关系,而类锁与类有关系。

那么我在这里可以猜测,如果有一个类A有一个成员方法:
public synchroniezed void b() {
...
}

现在我有两个线程t1,t2;同时我也有两个A的对象a1,a2;假设某个时刻,t1调用了对象a1的方法b,并且占用了对象a1的对象锁。而这个时候线程进行切换,t2调用了对象对象a2的方法b,那么t2还是会继续执行下去,因为a1与a2是同类不同对象。但是如果是类的话,就不可以。

刚刚想到了,为什么要这么设计。对于线程来说,最主要的是为了防止两个线程对同一个变量进行操作。但是对于对象来说,每个对象都是维护自己的成员变量,即使两个对象是同一个类产生的,但是他们的成员变量是不一样的。但是每个类的静态变量是唯一的,所以类的锁只能有一个。


然后,当Thread-0线程获得了这把锁后,应该是在对象中的锁内记录下当前占有自己的线程号,并把自己设置为已被占用。那么当Thread-0需要放弃锁的时候,我们只需要调用对象的某个方法(wait)来改变对象中锁的状态就可以了。而这一切和Thread-0是没有任何关系的。自然也轮不到 Thread-0对象来调用某个方法来改变另一个对象中的锁(这一点也说不通,我自己的锁凭什么让你来改)。

对于你这里的解释,我觉得部分有道理。但还是不很清晰。wait与notify是等待通知机制的实现。要知道,如果Java程序在执行,那么一定有一个线程在执行。

现在我的理解是:当Thread-0调用了wait方法的时候,必须把它放在同步synchronized中,主要是为了通过该锁作为一个媒介,将Thread-0线程放入到与该锁有关的堵塞队列中。那么另一个线程Thread-1可以调用notify方法通过相同的锁去堵塞队列中寻找Thread-0,同时激活它。

我可以打个比方:

public class B {
   public synchronized void active() {
         notify();
         ...
   }

   public synchronized void stop() {
         wait();
         ...
   }
}

如上类B有个对象b,现在有两个线程Thread-0, Thread-1。下面是我想的一种比较复杂的线程执行路线。
1,Thread-0调用b的stop方法,那么它首先获取对象b的对象锁。这个时刻切换到Thread-2
2,Thread-1执行,一直到调用了b的active方法,由于对象b的锁被Thread-0占领,Thread-1被放到与抢占锁有关系的等待队列中。
3,Thread-0执行,Thread-0调用wait方法,做得动作有,将Thread-0线程状态设置成忙,并且放入到与等待通知有关的堵塞队列中。释放对象b的锁。
4,Thread-1执行,发现现在对象b没有被占用。占用对象b的锁,进入方法体active。
5,调用notify方法,通过对象锁b去等待通知有关的堵塞队列中寻找到线程Thread-0,并且将Thread-0的状态设置成active状态,并且将Thread-0放到与抢占锁有关系的等待队列中。
6,Thread-1从对象b的active中返回,释放对象b的锁。
7,Thread-0获取对象b的锁,并且继续执行wait下面的代码。
8, Thread-0从对象b的stop方法中返回,释放对象b的锁。


这次就探讨到这里吧,呵呵!  以后再续
1 楼 Heart.X.Raid 2009-12-29  
这个问题我也遇到过: 用线程调用抛出一个 java.lang.IllegalMonitorStateException: current thread not owner异常。必须用同步块调用(也就是公共数据区对象)

我是这样理解的。

首先,我们都知道JVM会给每一个对象都分配唯一的一把锁。这把锁是在对象中的。

然后,当Thread-0线程获得了这把锁后,应该是在对象中的锁内记录下当前占有自己的线程号,并把自己设置为已被占用。那么当Thread-0需要放弃锁的时候,我们只需要调用对象的某个方法(wait)来改变对象中锁的状态就可以了。而这一切和Thread-0是没有任何关系的。自然也轮不到 Thread-0对象来调用某个方法来改变另一个对象中的锁(这一点也说不通,我自己的锁凭什么让你来改)。

因此,也就出现用改变公共数据区对象的锁的方法是通过共数据区对象本省来调用,和线程对象是没有关系的。

哈哈,想到这再往下想脑子就晕了。

我在javaeye上有博客,想交流可以常联系,谢谢。http://hxraid.iteye.com/blog/559043

相关推荐

    Java 中Object的wait() notify() notifyAll()方法使用

    主要介绍了Java 中Object的wait() notify() notifyAll()方法使用的相关资料,需要的朋友可以参考下

    sleep()、wait()、yield()和join()方法特点及区别.docx

    3.wait,notify和notifyAll只能在同步方法或同步代码块中调用,而sleep可以在任何地方调用; 4.sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常。(如果不是在同步方法或同步代码块中调用wait()方法,...

    java多线程系列(四)ReentrantLock的使用.docx

    创建多个condition对象 一个condition对象的signal(signalAll)方法和该对象的await方法是一一对应的,也就是一个condition对象的signal(signalAll)...Condition类的signalAll方法和Object类的notifyAll方法等效

    锁、生产者与消费者.pdf

    注意:上述方法只能被同步监听锁对象来调用,这也是为啥wait() 和 notify()方法都在 Object 对象中,因为同步监听锁可以是任意对象,只不过必须是需要同步线程的共同对象即可,否则别的对象调用会报错:  java.lang...

    100家大公司java笔试题汇总

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。) sleep...

    Java2023年最新免费面试题及答案附答案汇总.md 免费下载,不需要积分

    为什么线程通信的方法wait(), notify()和notifyAll()被定义在Object 类里 遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么 String str="i"与 String str=new String("i")一样吗 用过ConcurrentHashMap,...

    jstack生成的Thread Dump日志.docx

    只有当别的线程在该对象上调用了 notify()或者notifyAll()方法,"Wait Set"队列中的线程才得到机会去竞争,但是只有一个线程获得对象的Monitor,恢复到运行态。"Wait Set"中的线程在Thread Dump中显示的状态为 in ...

    java多线程设计模式详解(PDF及源码)

    wait set——线程的休息室 wait方法——把线程放入wait set notify方法——从wait set拿出线程 notifyAll方法——从wait set拿出所有线程 wait、notify、notifyAll是Object类的方法 线程的状态移转 跟线程有关的其他...

    高级开发并发面试题和答案.pdf

    描述一下notify和notifyAll区别; synchronized关键字加在静态方法和实例方法的区别; 用锁的注意点; cas机制可能导致的问题ABA,什么是ABA; 程序开多少线程合适; 实现一下DCL(双重检查锁) stream 和 parallel...

    多线程编程(电子书)

    Java自1995年面世以来得到了广泛得一个运用,但是对多...在Java 5.0之前Java里的多线程编程主要是通过Thread类,Runnable接口,Object对象中的wait()、 notify()、 notifyAll()等方法和synchronized关键词来实现的。

    java笔试题大集合及答案(另附各大公司笔试题)

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 62、同步和...

    jsp内置对象的用法

    4 void copy(Object obj) 把此Object拷贝到指定的Object对象中 5 Object clone() 克隆此Object对象 6 String toString() 把此Object对象转换成String类的对象 7 void notify() 唤醒一个等待的线程 8 void ...

    Java中线程的等待与唤醒_动力节点Java学院整理

    在Object.java中,定义了wait(), notify()和notifyAll()等接口。wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。下面通过本文给大家介绍Java中线程的等待与唤醒知识,感兴趣的...

    knowledge-interview:知识学习

    notify() notifyAll() toString() wait() String String、StringBuffer、StringBuilder三者的区别: 都在java.lang 包下 String使用final修饰,不可变,每次字符串变更都是创建新的字符串,String s = “a”+"b"除外...

    java 面试题 总结

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 14、Overload...

    LeetCode判断字符串是否循环-java:Java

    LeetCode判断字符串是否循环 知识点总结 java基础 1、使用迭代器和for each循环查看集合元素时只能获得元素的值,不能改变元素 ...object的方法:wait(notify,notifyall),thread的方法:(sleep、join),结束

    超级有影响力霸气的Java面试题大全文档

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 17、...

    Practical Java(中文版(繁体+简体))

    實踐53:優先使用notifyAll()而非notify() 185 實踐54:針對wait()和notifyAll()使用旋鎖(spin locks) 187 實踐55:使用wait()和notifyAll()替換輪詢循環(polling loops) 191 實踐56:不要對locked object(㆖鎖...

    进销存系统文档作业例子

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 14、...

    关于JAVA面试的100题及其答案

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。

Global site tag (gtag.js) - Google Analytics