在面试中经常会被问到多线程的知识,而在这个知识范围内,我们也会被问到关于wait、notify等这些方法。
为什么线程通信的方法wait()、notify()、notifyAll()被定义在Object类里面?而sleep定义在Thread类里面?
我们要从java语言本身设计层面理解这样的问题。
wait()、notify()、notifyAll()被定义在Object类里面?
从使用代码来看,首先在代码里面,我们创建了一个Object对象,然后我们synchronized锁定的便是object,从synchronized(Java并发编程)的底层实现原理看出,当进入synchronized时当前线程便会持有monitor,如果不能获取到这个monitor的话,wait方法是会抛异常的。
其实我们从代码中还可以看出这样的一个问题,就是我们在两个线程中所用的是一个对象,在Thread1中我们使用object对象来调用wait方法,然后在Thread2中使用object去调用notify方法来唤醒线程调用wait方法的线程,当前代码的执行顺序的结果是:
线程Thread-0开始执行线程
Thread-1调用了notify()线程
Thread-0获取到了锁
这从另一个角度也证明了,wait是用来释放锁的。从上面的整个代码逻辑中,可以看出wait、notify、notifyAll被设计在Object类中的原因是,JAVA提供的锁是对象级的而不是线程级的,每个对象都有个锁,而线程是可以获得这个对象的。因此线程需要等待某些锁,那么只要调用对象中的wait()方法便可以了。而wait()方法如果定义在Thread类中的话,那么线程正在等待的是哪个锁就不明确了。这也就是说wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中是因为锁是属于对象的原因。
sleep为什么定义在Thread类里面?
对于sleep为什么被定义在Thread中,我们只要从sleep方法的作用来看就知道了,sleep的作用是:让线程在预期的时间内执行,其他时候不要来占用CPU资源。从上面的话术中,便可以理解为sleep是属于线程级别的,它是为了让线程在限定的时间后去执行。而且sleep方法是不会去释放锁的。
别的原因:因为每个对像上都有一把锁(当然为了节省内存,锁极可能不是一开始就分配好的)。java锁在对象头上。为了让所有的类具有线程的能力。
javadoc里也提到这么一段话:
This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:
By executing a synchronized instance method of that object.
By executing the body of a synchronized statement that synchronizes on the object.
For objects of type Class, by executing a synchronized static method of that class.
wait()在这几个条件下能用:是如果在没有使用多线程的程序里,如最简单的helloworld,调用了wait,这样会产生什么样的效果,使得主线程等待吗,那么又由那个对象来激活它呢,或者出于无知,调用了notfiy会有什么结果?按照以上条件,会抛出异常吧!