应用场景
两个线程任务要相互沟通,相互通知,那么就要使用线程通信技术。 比如等待唤醒机制。
注意,这里是两个【线程任务】,而不是两个线程,两个概念一定一定要分清楚,不要混。
其实,多个线程中,为了线程安全,使用同一个锁,已经隐约间有线程通信内味儿了。
线程通讯的前提也是使用同一个锁。
小二上菜
比如饭店里的厨师和小二
客人点菜,厨师做菜,小二上菜。
三者之间是有联系的。
厨师做好了菜,要通知小二上菜。
客人来吃饭,小二要通知厨师做菜。
这就是两个线程任务,
客人负责吃菜,等菜。
厨师负责做菜,等客人。
小二就是多线程中的锁对象。
线程状态
新建(NEW): 新new的线程(尚未启动)。
运行(RUNNABLE): 正在运行的线程(已调用start)。
受阻塞(BLOCKED):执行到同步代码块,没有锁,等待获取锁的线程。
无限等待(WAITING): 当调用了wait()方法后,线程会变成无限等待。
计时等待(TIMED_WAITING): 当调用sleep(毫秒值),wait(毫秒值)方法后会进入到计时等待。
退出(TERMINATED): 当线程执行完run方法,或者调用了线程的stop方法,线程会变成退出状态。
细节:
执行notify之后,当前线程不会马上释放对象锁,呈wait状态的线程也并不能马上获取该对象锁。
要等到执行notify方法的线程将程序执行完,也就是退出synchronized代码后,当前线程才会释放锁。
无限等待状态的线程会变更为受阻塞状态,等另一个线程释放锁后,就会拿到锁。
线程可能的生命周期:
新建->运行->受阻塞->运行
新建->运行->无线等待->运行
新建->运行->无线等待->受阻塞
新建->运行->计时等待->运行
新建->运行->及时等待->受阻塞
wait/notify
wait可以让线程等待, notify可以唤醒等待的线程。
这两个方法一般用于线程通信, 或者称为等待唤醒机制。
wait和notify方法是属于Object的,而不是Thread。
void wait(): 让线程等待,直到其他线程唤醒它。
void wait(long timeout): 让线程等待,直到其他线程唤醒它或者参数指定的时间(毫秒值)已到。
void notify(): 唤醒一个线程。
void notifyAll(): 唤醒所有的线程。
Tips:
调用wait方法,会释放锁,调用sleep方法不会释放锁。
哪个锁对象调用的notify方法,唤醒的就是哪个锁wait等待的线程。
为什么wait/notify是Object类方法,而不是Thread
首先,java语言为什么叫java语言。
其次,wait方法为什么是Object类,你个杠精。
最后,等待唤醒方法是由锁来使用的,锁类型是任意类型,那么等待唤醒方法自然也就是Object类咯。
如果是Thread类,那么实现Runable接口的可不是线程类,难道多线程只能采用继承Thread类的方法吗。
wait和sleep方法有什么不同
1、wait进入等待状态会释放锁,sleep不会释放锁。
2、wait是Object类的方法,sleep是Thread的方法。
3、wait必须在同步代码块使用,sleep任意。
4、wait可以指定时间进入计时等待也可以不指定进入无限等待,sleep必须指定时长。