Java线程间通信
Java线程间通信
总结下Java线程间通信的编程技巧。
Java中线程处于Runnable状态
- 调用sleep方法超过指定时间
- 线程调用的阻塞I/O返回
- 线程成功获得试图同步的监视器
- 线程在等待某个通知,其他线程发出通知
- 处于挂起状态调用了resume恢复方法
Java中线程处于阻塞状态
- 线程调用sleep方法
- 线程调用阻塞式I/O,调用返回
- 线程试图获取一个同步监视器,但该同步监视器正在被其他线程使用
- 线程等他某个通知
- 程序调用suspend方法将线程挂起,但谨慎调用该方法。
线程间通信促进资源的共享,加大线程的交互性。
不使用等待/通知机制的线程间通信
不使用等待/通知机制的进行线程间通信可以使用轮询。例子如下:
原理:每个线程都在while循环下轮询共享变量,根据共享变量的值判断下一步的执行。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
32import java.util.Date;
public class ITCTest {
private static boolean status = true;
private static class Thread1 extends Thread {
public void run() {
while (status) {
System.out.println("time is " + new Date());
}
}
}
public static class Thread2 extends Thread {
public void run() {
while (status) {
System.out.println("time is " + new Date());
}
}
}
public static void main(String[] args) {
Thread t1 = new Thread1();
Thread t2 = new Thread2();
t1.start();
t2.start();
delay();
status = false;
}
}
如果线程轮询时间过小,消耗更大的CPU资源,如果轮询时间过大,则可能错过数据的更新。
等待/通知机制 wait/notify
wait:暂停线程的等待,调用该方法的线程释放共享资源的锁,运行态转换为就绪态,加入等待队列。wait方法可以传入参数,指定等待时间。
notify:通知线程继续运行,随机唤醒等待队列中的一个线程。
注意:调用wait方法会释放锁,但调用notify方法并不释放锁,只有当notify所在的synchronized的代码块被执行完毕后才被调用。
例子: (生产者/消费者模型在代码库中)
1 |
|
注意:
- 当线程在wait()状态下,调用interrupt()方法会出现InterruptedException异常。
通过管道进行线程通信
- 字节流
- 字符流
这部分参考IO模块的实现
join方法的使用
阻塞当前调用join的线程,直到被阻塞的线程返回。可以传入long类型的参数指定timeout参数。
- join 方法的内部实现采用 wait
- sleep 方法调用后不释放锁
ThreadLocal
ThreadLocal线程本地:每个线程都有同一个变量的独有拷贝。拥有get、set接口。
实现原理:
有一个Map维护线程对象和值的映射。
例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ThreadLocalBasic {
static ThreadLocal<Integer> local = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
Thread child = new Thread() {
public void run() {
System.out.println("child thread initial: " + local.get());
local.set(200);
System.out.println("child thread final: " + local.get());
}
};
local.set(100);
child.start();
child.join();
System.out.println("main thread final: " + local.get());
}
}
以上。