线程通信
两个线程间实现通信,如果轮询时间间隔小,浪费cpu资源,如果轮询时间间隔大,有可能会取到与期望值不一样的数据。
Wait 和 notify的实现
Wait方法
是使当前执行代码的线程进行等待。但是在调用wait方法之前,线程必须获得该对象的对象级别锁。只能在同步方法或同步代码块中调用wait方法,在执行wait方法后,当前线程释放同步锁。同理notify方法
也要在同步方法或同步代码块中调用。注意:当执行notify方法后,当前线程不会马上释放该对象,wait状态的线程也不会马上获取该对象锁,需要等执行notify方法的线程执行完(退出synchronized同步方法或同步代码块)。Wait方法在同步方法或同步代码块里运行,wait方法可以使调用该方法的线程释放同步对象锁。
Wait方法使线程停止,notify使停止的线程继续运行。
例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49public class ThreadA extends Thread{
private Object object;
public ThreadA(Object object) {
this.object = object;
}
public void run() {
synchronized (object){
System.out.println("wait开始,wait time="+System.currentTimeMillis());
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait结束,wait time="+System.currentTimeMillis());
}
}
}
public class ThreadB extends Thread {
private Object object;
public ThreadB(Object object) {
this.object = object;
}
public void run() {
synchronized (object){
System.out.println("notify开始,notify time="+System.currentTimeMillis());
object.notify();
System.out.println("notify结束,notify time="+System.currentTimeMillis());
}
}
}
public class Test {
public static void main(String[] args) {
Object object=new Object();
ThreadA threadA=new ThreadA(object);
threadA.start();
ThreadB threadB=new ThreadB(object);
threadB.start();
}
}
线程的生命周期
新建状态
当程序使用new创建一个线程后,就处于新建状态。
就绪状态(可运行状态)
当线程调用start()后,该线程就处于就绪状态,
这是一个准备阶段
。
运行状态
如果线程抢到cpu资源,此线程就处于
运行状态
。
阻塞状态
阻塞状态是线程因为某种原因放弃CPU使用权,使cpu处于空闲状态。
线程转化阻塞状态
- 线程调用
sleep方法
,主动放弃占有的处理资源。- 线程调用了
阻塞式IO已经返回
,在该方法返回前,该线程被阻塞。- 线程试图获取一个
同步监视器
,但该同步监视器正被其他线程所持有。- 线程在等待某个通知。
- 线程调用了suspend方法将该线程挂起。
阻塞状态重新进入就绪状态
因为线程运行一段时间后,有其他优先级高的线程抢占cpu
重新进入就绪状态有以下情况:
- 调用
sleep方法
后经过的时间超过指定休眠时间。- 线程调用的
阻塞IO已经返回
,阻塞方法执行完毕。- 线程成功获取试图
同步的监视器
。- 线程正在
等待某个通知
,其他线程发出了一个通知。- 处于挂起的线程调用了
resume复方法
。