java之Thread.sleep(long)与object.wait()/object.wait(long)的区别及相关概念梳理(good)

简介: 一、Thread.sleep(long)与object.wait()/object.wait(long)的区别sleep(long)与wait()/wait(long)行为上有些类似,主要区别如下:1.Thread.sleep(long)是属于Thread类的静态方法。

 

一、Thread.sleep(long)与object.wait()/object.wait(long)的区别
sleep(long)与wait()/wait(long)行为上有些类似,主要区别如下:
1.Thread.sleep(long)是属于Thread类的静态方法。其基本语义是使当前运行的线程暂停一段时间。实现细节是把当前线程放入就绪线程队列中,直到睡眠时间到期才可被调度为执行线程(在时间到期前无法被调度为执行线程)。此方法可以在sychronized代码块中,调用此方法不释放对象锁;也可以不在sychronized代码块中。此方法的作用线程一定是当前运行的线程(如果代码在一个线程类中,不一定是代码所在的线程实例),即使是在线程对象上调用sleep(long)或调用Thread.currentThread().sleep(long)。


2.object.wait()是属于类实例(Object及其子类实列,也包括Class类实例)的方法。
其基本语义是使当前线程等待,直到被通知,默认是this.wait()。实现细节是把当前线程放入阻塞线程队列中,并把当前线程注册为指定对象的监听器,并锁释放指定对象的锁;当被notify/notifyAll通知时,重新争取指定对象的锁,并把当前线程从指定对象的监听器中移除,把当前线程从阻塞队列放入就绪队列,等待被调度。
此方法必须在sychronized代码块中,且锁定的对象要与等待通知来源的对象一致。而wait(long)方法阻塞时放入的是就绪队列,等待时间到期或被通知就可被调度,其他与wait()方法相同。
如果当前线程不是对象所得持有者,该方法抛出一个java.lang.IllegalMonitorStateException 异常”
http://blog.csdn.net/intlgj/article/details/6245226

注:从上可基本认识到线程的执行、就绪、阻塞三种状态的切换,以及线程的调度(操作系统调度线程)和就绪线程队列、阻塞线程队列(实际实现可能更复杂,比如优先级,调度策略等)。可认识到object(包括Class类的实例)的wait/notify/notifyAll的对象监听和通知事件模式,以及对象上的锁、锁队列(实际实现可能更复杂,比如优先级,锁争用等)、阻塞线程监听队列(notify时只通知一个监听器,具体调度未知,另有自动唤醒,条件唤醒)。

http://blog.csdn.net/qingmingcom/article/details/6590967

 

    wait()方法与notify()必须要与synchronized(resource)一起使用。也就是wait与notify针对已经获取了resource锁的线程进行操作
从语法角度来说就是Obj.wait(),Obj.notify必须在synchronized(Obj){...}语句块内。
从功能上来说wait()线程在获取对象锁后,主动释放CPU控制权,主动释放对象锁,同时本线程休眠。直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁,并继续执行。
相应的notify()就是对对象锁的释放操作
【因此,我们可以发现,
wait和notify方法均可释放对象的锁,但wait同时释放CPU控制权,即它后面的代码停止执行,线程进入阻塞状态,而notify方法不立刻释放CPU控制权,而是在相应的synchronized(){}语句块执行结束,再自动释放锁
释放锁后,JVM会在等待resoure的线程中选取一线程,赋予其对象锁,唤醒线程,继续执行。这样就提供了在线程间同步、唤醒的操作。
Thread.sleep()与Object.wait()二者都可以暂停当前线程,释放CPU控制权,主要的区别在于Object.wait()在释放CPU同时,释放了对象锁的控制
而在同步块中的
Thread.sleep()方法并不释放锁,仅释放CPU控制权。

  1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。

  2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁,或者叫管程)

  3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;

  4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;

     在Java中,是没有类似于PV操作、进程互斥等相关的方法的。JAVA的进程同步是通过synchronized()来实现的,需要说明的是,Java的synchronized()方法类似于操作系统概念中的互斥内存块,在Java中的Object类对象中,都是带有一个内存锁的,在有线程获取该内存锁后,其它线程无法访问该内存,从而实现Java中简单的同步、互斥操作。明白这个原理,就能理解为什么synchronized(this)与synchronized(static XXX)的区别了,synchronized就是针对内存区块申请内存锁,this关键字代表类的一个对象,所以其内存锁是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加锁,相当于对类加锁,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例。如果需要在线程间相互唤醒就需要借助Object类的wait()方法及nofity()方法。

http://blog.csdn.net/lingzhm/article/details/44940823

什么是monitor?

在HotSpot虚拟机中,monitor采用ObjectMonitor实现。

每个线程都有两个ObjectMonitor对象列表,分别为free和used列表,如果当前free列表为空,线程将向全局global list请求分配ObjectMonitor。

ObjectMonitor对象中有两个队列:
_WaitSet 和 _EntryList,用来保存ObjectWaiter对象列表;
_owner指向获得ObjectMonitor对象的线程。

_WaitSet :处于wait状态的线程,会被加入到wait set;
_EntryList:处于等待锁block状态的线程,会被加入到entry set;

ObjectWaiter

ObjectWaiter对象是双向链表结构,保存了_thread(当前线程)以及当前的状态TState等数据, 每个等待锁的线程都会被封装成ObjectWaiter对象。

http://www.jianshu.com/p/f4454164c017

 

我刚开始深入研究多线程,一直认为Object.wait()/Condition.await()让当前线程阻塞的同时,也会释放当前线程对该condition对象的锁。在之前的一些测试代码中也显示wait后,线程上的锁被释放了。
查看Object.wait()API 描述如下:

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0). 
    The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method.
 The thread then waits until it can re-obtain ownership of the monitor and resumes execution.

其中“the thread releases ownership of this monitor” 说道当前线程会释放这个对象监控器的所有权。

问题一:这里的monitor怎么理解?监视器(monitor)和锁是什么关系? 这个monitor就是一个术语,或者是一个特殊的类(只包含私有域),但是在java中并没有严格遵守这个概念。个人认为可以简单的理解为锁。

同样的,Condition.await()方法中也有类似描述。
The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes...
也说道,调用await()有,这个条件对象关联的锁被“原子级地”释放。。。

问题二:这个原子级的释放是什么意思? “原子级”其实就是为了保证一个操作的完整性,原子级的释放保证了一个原子操作不会因为线程的突然挂起或者说阻塞而破坏这次操作。

这都能说明调用wait()或者await()后,当前线程会释放该条件对象关联的锁吧?


两个线程用object1做 wait/notify, 是这样:
thread1 得到object1 的 monitor, 调用 object1.wait()
- 释放object1 的 monitor, thread1 wait;

thread2 得到 object1 的 monitor, 调用 object1.notify()
- 激活thread1, 释放object1 的 monitor;

thread1 得到 object1 的 monitor, 从object1.wait()返回, thread1接着执行.
关于monitor, 这个是多进程/线程同步的 一个术语, 见:
Operating Systems Design and Implementation, Third Edition
section 2.2

A monitor is a collection of procedures, variables, and data structures that are all grouped together in a special kind of module or package. 
Processes may call the procedures in a monitor whenever they want to, but they cannot directly access the monitor's internal data structures from procedures declared outside the monitor. 
This rule, which is common in modern object-oriented languages such as Java, was relatively unusual for its time, although objects can be traced back to Simula 67.

In all cases, before this method can return the current thread must
re-acquire the lock associated with this condition. When the
thread returns it is guaranteed to hold this lock.

会释放,其他线程执行Condition.signal(),之前的线程会重新获得锁,继续执行,
AbstractQueuedSynchronizer.java 第2040行,释放锁

https://segmentfault.com/q/1010000002390706

 

相关文章
|
22天前
|
Java 程序员 调度
Java 高级面试技巧:yield() 与 sleep() 方法的使用场景和区别
本文详细解析了 Java 中 `Thread` 类的 `yield()` 和 `sleep()` 方法,解释了它们的作用、区别及为什么是静态方法。`yield()` 让当前线程释放 CPU 时间片,给其他同等优先级线程运行机会,但不保证暂停;`sleep()` 则让线程进入休眠状态,指定时间后继续执行。两者都是静态方法,因为它们影响线程调度机制而非单一线程行为。这些知识点在面试中常被提及,掌握它们有助于更好地应对多线程编程问题。
55 9
|
27天前
|
安全 Java 程序员
Java面试必问!run() 和 start() 方法到底有啥区别?
在多线程编程中,run和 start方法常常让开发者感到困惑。为什么调用 start 才能启动线程,而直接调用 run只是普通方法调用?这篇文章将通过一个简单的例子,详细解析这两者的区别,帮助你在面试中脱颖而出,理解多线程背后的机制和原理。
60 12
|
28天前
|
缓存 Java 开发者
Java字面量详解:概念、分类与使用实例
本文介绍了Java字面量的概念、分类及应用。
49 11
|
2月前
|
存储 Java 程序员
Java的基础概念一
### Java编程基础简介 #### 一、注释 注释用于解释代码,不会参与编译和运行。Java支持三种注释: - **单行注释**:以 `//` 开头。 - **多行注释**:以 `/* ... */` 包围。 - **文档注释**:通常用于生成开发文档。 #### 二、关键字 关键字是被Java赋予特定含义的英文单词,全部小写,且在代码编辑器中有特殊颜色标记。常用的如 `class` 表示定义一个类。
Java的基础概念一
|
1月前
|
Java 数据安全/隐私保护
Java的基础概念(二)
本文介绍了Java编程语言中的运算符和表达式,涵盖算术运算符、赋值运算符、关系运算符、逻辑运算符、三元运算符等。重点讲解了算术运算符的使用,如加减乘除取余,并强调了整数除法和取余的特殊性。同时,详细说明了隐式转换与强制转换的概念及应用场景,以及字符串和字符的拼接规则。通过多个案例演示了不同运算符的实际应用,包括数值拆分、自增自减、三元表达式的使用等。最后简要提及了运算符的优先级,指出小括号具有最高优先级。
|
2月前
|
JSON Java Apache
Java基础-常用API-Object类
继承是面向对象编程的重要特性,允许从已有类派生新类。Java采用单继承机制,默认所有类继承自Object类。Object类提供了多个常用方法,如`clone()`用于复制对象,`equals()`判断对象是否相等,`hashCode()`计算哈希码,`toString()`返回对象的字符串表示,`wait()`、`notify()`和`notifyAll()`用于线程同步,`finalize()`在对象被垃圾回收时调用。掌握这些方法有助于更好地理解和使用Java中的对象行为。
|
2月前
|
Java
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
今日分享的主题是如何区分&和&&的区别,提高自身面试的能力。主要分为以下四部分。 1、自我面试经历 2、&amp和&amp&amp的不同之处 3、&对&&的不同用回答逻辑解释 4、彩蛋
|
3月前
|
Java 程序员
Java社招面试题:& 和 && 的区别,HR的套路险些让我翻车!
小米,29岁程序员,分享了一次面试经历,详细解析了Java中&和&&的区别及应用场景,展示了扎实的基础知识和良好的应变能力,最终成功获得Offer。
107 14
|
2月前
|
Java
java中面向过程和面向对象区别?
java中面向过程和面向对象区别?
36 1
|
3月前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
104 8