java thread有五种状态类型
新建状态(new):新创建了一个线程对象。
就绪状态(runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取cpu的使用权。
运行状态(running):就绪状态的线程获取了cpu,执行程序代码。
阻塞状态(blocked):塞状态是线程因为某种原因放弃cpu使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
死亡状态(dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
当我们调用线程类的<code>sleep()、suspend()、yield()、wait()</code>等方法时会导致线程进入阻塞状态。
wait(): 调用任何对象的wait()方法会让当前线程进入等待,直到另一个线程调用同一个对象的notify()或notifyall()方法。
notify():唤醒因调用这个对象wait()方法而阻塞的线程。
首先,<code>sleep()、suspend()、yield ()</code>等方法都隶属于 thread 类,但<code>wait()/notify()</code>这一对却直接隶属于object 类,也就是说,所有对象都拥有这一对方法。初看起来这十分不可思议,但是实际上却是很自然的,因为这一对方法阻塞时要释放占用的锁,而锁是任何对象都具有的,调用对象的 wait() 方法导致线程阻塞,并且该对象上的锁被释放。而调用对象的notify()方法则导致因调用该对象的 wait() 方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。
其次,前面叙述的所有方法都可在任何位置调用,但是这一对方法却必须在 <code>synchronized</code>方法或块中调用,理由也很简单,只有在<code>synchronized</code> 方法或块中当前线程才占有锁,才有锁可以释放。同样的道理,调用这一对方法的对象上的锁必须为当前线程所拥有,这样才有锁可以释放。因此,这一对方法调用必须放置在这样的 <code>synchronized</code>方法或块中,该方法或块的上锁对象就是调用这一对方法的对象。若不满足这一条件,则程序虽然仍能编译,但在运行时会出现<code>illegalmonitorstateexception</code>异常。
最后,关于 wait() 和 notify() 方法再说明三点:
调用 notify() 方法导致解除阻塞的线程是从因调用该对象的 wait() 方法而阻塞的线程中随机选取的,我们无法预料哪一个线程将会被选择,所以编程时要特别小心,避免因这种不确定性而产生问题
除了 notify(),还有一个方法 notifyall() 也可起到类似作用,唯一的区别在于,调用 notifyall() 方法将把因调用该对象的 wait() 方法而阻塞的所有线程一次性全部解除阻塞。当然,只有获得锁的那一个线程才能进入可执行状态。
wait()和notify()必须成对存在。
先写一个计数线程类countthread:
再写一个测试类作为主线程:
运行结果:
生产者:
消费者:
打印结果: