`
freesoftman
  • 浏览: 318829 次
  • 性别: 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 同步方式 wait和notify/notifyall

    在Java中,`wait()`, `notify()`, 和 `notifyAll()` 是Java Object类的三个方法,它们在实现线程间通信和协作时扮演着关键角色。这些方法主要用于解决线程等待和唤醒的问题,是基于Java Monitor(监视器)模型的。 ...

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

    Java 中Object的wait() notify() notifyAll()方法使用 在Java并发编程中,Object的wait()、notify()和notifyAll()方法是非常重要的概念,这三个方法都是Object类的方法,可以认为任意一个Object都是一种资源(或者...

    Java多线程中wait、notify、notifyAll使用详解

    Java中多线程编程中,wait、notify、notifyAll三个方法是非常重要的,它们都是Object对象的方法,用于线程之间的通信。下面我们将详细介绍这三个方法的使用和作用。 一、wait()方法 wait()方法是使当前线程自动...

    java之wait,notify的用法([ 详解+实例 ])

    wait方法是Object类的一个方法,用于让当前线程进入等待状态,直到其他线程调用notify或notifyAll方法来唤醒它。在wait方法中,当前线程会释放它所占有的锁,并进入等待状态。wait方法可以带有参数,指定等待的时间...

    wait_notify_demo

    `wait()`、`notify()`和`notifyAll()`是Java中的三个关键字,它们属于Object类的方法,主要用于线程间的通信,尤其在实现生产者消费者模式时发挥着重要作用。本文将深入探讨这些方法以及如何在实际场景中应用它们。 ...

    Java多线程wait和notify

    在Java中,`wait()` 和 `notify()` 方法是实现线程间通信和协作的重要工具,它们属于 `java.lang.Object` 类,这意味着所有类都默认继承了这两个方法。本文将详细探讨如何使用 `wait()` 和 `notify()` 来控制子线程...

    java中几个notify、wait使用实例

    `wait()`、`notify()`和`notifyAll()`方法是Java中实现线程同步的关键工具。正确使用它们可以有效避免线程间的竞争条件和死锁问题,同时也能实现线程间的高效通信。在实际开发中,应根据具体的应用场景选择合适的...

    Java的wait(), notify()和notifyAll()使用心得

    Java中的`wait()`, `notify()`, 和 `notifyAll()` 是多线程编程中的关键工具,它们用于在并发环境中协调线程间的交互。这些方法都定义在`java.lang.Object`类中,因为它们与对象的监视器(monitor)概念密切相关。...

    Object.wait()与Object.notify()的用法详细解析

    Java中的`Object.wait()`、`Object.notify()`以及`Object.notifyAll()`是多线程编程中的核心方法,它们用于实现线程间的协作与通信。这些方法是`Object`类的最终原生(`final native`)方法,这意味着它们的实现位于...

    等待机制与锁机制wait notify

    本文将深入探讨`wait`、`notify`以及`notifyAll`这三个关键字的使用及其背后的原理,帮助你理解如何在实际编程中有效地利用它们来解决线程同步问题。 首先,我们需要了解Java中的对象锁。每个Java对象都有一个内置...

    Java多线程同步(wait()notify()notifyAll())[文].pdf

    本文将深入探讨Java中的wait()、notify()和notifyAll()方法,以及synchronized关键字和原子操作在多线程环境中的应用。 1. **wait()方法**: - wait()是Object类的一个方法,它的作用是让当前线程暂停执行并释放它...

    Java wait和notifyAll实现简单的阻塞队列

    在 Java 中,wait 和 notifyAll 是两个非常重要的方法,它们都是在 Object 类中声明的,用于实现线程之间的通信和同步。wait 方法会使调用线程进入等待状态,并释放所持有的对象锁,而 notifyAll 方法则会去唤醒当前...

    深入理解Wait、Notify和Wait与sleep区别

    首先,`wait()`, `notify()`和`notifyAll()`是Object类中的方法,它们主要用于线程间通信和协作。这些方法只能在同步环境中(如`synchronized`块或方法)使用,否则会抛出`IllegalMonitorStateException`。它们的...

    Java的sychronized、wait和notify范例

    在提供的压缩包文件`java_sychronization`中,可能包含了一些示例代码,用于演示如何在Java中使用`synchronized`关键字以及`wait()`和`notify()`方法。通过研究这些样例,你可以更深入地了解这些工具的用法和效果。...

    主线程去控制子线程wait与notify

    在Java中,使用`wait()`, `notify()`, 和 `notifyAll()`必须在同步块或者同步方法中,因为它们涉及到对共享资源的访问。这是为了避免出现竞态条件,确保只有一个线程在执行这些操作。 主线程控制子线程的`wait()`和...

    wait,notify等线程知识.pdf

    Java中的多线程协同工作是通过一系列的同步机制来实现的,其中wait、notify和notifyAll是基于对象监视器的同步原语。这些方法在Java的Object类中定义,主要用于线程间的通信和协作,确保资源的安全访问。下面将详细...

    Java notify和notifyAll的区别和相同

    Java中的`notify`和`notifyAll`是多线程编程中的关键方法,它们用于线程间的通信,特别是在处理同步机制时。这两个方法都是在`Object`类中定义的,因此可以应用于任何Java对象。 首先,我们需要理解Java的同步机制...

    一个理解wait()与notify()的例子

    通过本示例代码的学习,我们可以深入了解`wait()`与`notify()`方法的工作原理及其在Java多线程编程中的应用。这两个方法通过释放和重新获取锁的方式,有效地实现了线程间的通信和同步,是Java并发控制的重要组成部分...

    基于Java多线程notify与notifyall的区别分析

    Java中的多线程编程是构建高效并发应用的关键技术之一,其中`wait()`、`notify()`和`notifyAll()`是Java对象锁机制中的三个关键方法,它们位于`java.lang.Object`类中,主要用于线程间通信。本文将深入探讨`notify()...

Global site tag (gtag.js) - Google Analytics