返回信息流java中线程获得某个对象的锁后,如果某些条件不满足可以调用锁对象的wait()方法进入等待状态。在一个线程已经获得锁的情况下,其他线程被阻塞,这两种状态有什么区别呢?
当调用notify()方法时,只会唤醒那些调用过wait()方法的线程吗?notify会对被阻塞的线程产生影响吗?
这是一条镜像帖。来源:北邮人论坛 / java / #55845同步于 2017/4/2
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
线程的等待状态和阻塞状态有什么区别呢?
liujinhong
2017/4/2镜像同步7 回复
订阅后,新回复会通过你的通知中心匿名送达。
7 条回复
本质上没有区别,都是因为某些原因而暂时不能继续执行。
比如synchronize(obj),如果阻塞,原因是别的线程获取了那个锁;Object.wait()如果阻塞,是因为主动要求等待,且还没有被叫醒。还有几个例子:InputStream.read()阻塞,是因为输入流还没有读到数据,一般是文件读取速度比较慢(硬盘当然比内存慢,网络更慢);SocketChannel.read(buf)阻塞,也是因为网络读取速度慢;Thread.sleep阻塞,是主动要求等待,等待一段时间之后会被叫醒。
所有的线程阻塞,从操作系统的角度看,都是一个作业要求暂停,或者因某些原因被暂停;在一定条件下被叫醒。比如:
Linux下,锁一般是用futex系统调用来实现的。一个线程想获得锁而不得的时候,需要用futex_wait命令来让Linux内核让自己阻塞;等别的线程把锁解开的时候,用futex_wake让Linux内核把等待的线程叫醒。Linux里,read系统调用可以用于磁盘文件,也可以用于socket,如果硬盘读取慢,或者等待网络传输,也会让发出read系统调用的线程阻塞。当硬盘数据到了,或者网络数据到了,就会叫醒那个线程。
L4微内核,内核不懂阻塞型的锁,也不懂文件系统和socket。要实现锁,就需要自己写一个锁服务器(一个线程)。线程想让自己阻塞的时候,就像那个服务发个消息,包含一个wait请求,然后试图从那个服务器接收消息,接收消息会一直阻塞,直到收到消息。那个服务负责同步不同线程的wait和wake请求,当一个线程要让另一个线程醒过来的时候,给服务器发wake消息,服务器给那个正在阻塞的线程随便发一个消息,它就醒过来了。也就是说,内核不负责实现futex了,需要在用户态自己写一个服务器来实现(或者让别人帮我写一个)。在微内核上实现文件系统也类似,要么在当前线程里控制硬件,要么把硬件控制单独交给一个特权线程,别的线程用消息来通信。还是那句话,从另一个线程接收消息,会阻塞,直到收到为止。在微内核上编程,这些锁、文件系统什么的都要自己实现。
总之,阻塞就是暂时不能继续执行了。不同类型的阻塞,本质上是一回事。
感谢暖神!
【 在 nuanyangyang 的大作中提到: 】
: 本质上没有区别,都是因为某些原因而暂时不能继续执行。
: 比如synchronize(obj),如果阻塞,原因是别的线程获取了那个锁;Object.wait()如果阻塞,是因为主动要求等待,且还没有被叫醒。还有几个例子:InputStream.read()阻塞,是因为输入流还没有读到数据,一般是文件读取速度比较慢(硬盘当然比内存慢,网络更慢);SocketChannel.read(buf)阻塞,也是因为网络读取速度慢;Thread.sleep阻塞,是主动要求等待,等待一段时间之后会被叫醒。
: 所有的线程阻塞,从操作系统的角度看,都是一个作业要求暂停,或者因某些原因被暂停;在一定条件下被叫醒。比如:
: ...................
如果按4、5楼的定义的话,wait并不进入“等待”状态。wait也是阻塞。wait操作的是每个对象自带的condition variable,和锁是类似的,在wait阻塞的时候是不能调度到cpu上执行的,必须被notify才有执行机会。就连Thread.sleep都是阻塞,不睡足一定时间也是不可以调度到cpu上执行的,即使有时间片也不行。
翻了一下《深入理解Java虚拟机》,在Java中线程的状态有新建,运行,等待,阻塞和结束这几个状态。“阻塞状态”和“等待状态”的区别是:“阻塞状态”在等待着获取一个排他锁,这个事件将在另一个线程放弃这个锁的时候发生。而“等待状态”则是在等待一段时间,或者唤醒动作的发生。在程序等待进入同步区域的时候,线程将进入这种状态。
简单认为,阻塞和等待这两个状态都是某些条件不满足导致线程被挂起,暂停,具体到Java的线程模型:
1. 等待和阻塞都不会被分配cpu时间
2. 阻塞状态是等待获取一个排他锁,等待状态是在等待进入同步代码块的条件满足
线程从等待状态被唤醒的时候,会从上次等待的地方继续执行。线程在收到别的线程的唤醒信号后,也必须重新获得一个对象的排他锁,这个过程中貌似又是一个阻塞的过程。
4,5楼应该是操作系统线程状态的理解。等待状态相当于ready的状态,线程等待cpu的调度。而阻塞状态是在等待资源。因此Java中线程的状态和操作系统线程状态的对应如下,这样的关系并没有什么太多的意义,关键还是要真正明白线程的状态和状态之间的转换。
java中Running——>Running and Ready
java中Waiting,Blocked——>Blocked(Waiting)