传统线程同步通信
讲过了线程互斥,接下来了解一下线程协作,使得多个任务彼此之间可以一起工作去解决某个问题。
传统定时器和线程互斥技术
当任务协作时,关键是这些问题之间的握手。为了实现这种握手我们使用了相同的基础特性:互斥。互斥能够确保只有一个任务可以响应某种信号,这样就可以排除任何可能的竞争条件。在互斥之上,我们为任务添加了一种途径,可以直接将自身挂起
线程通信
- wait():线程进入等待状态直到它被通知,释放锁
- notify():接触一个线程的wait阻塞状态
- notifyAll(): 接触所有线程的wait阻塞状态
例子:一个工人盖房子先要先抹水泥再砌砖,需要垒10排砖,垒一排砖分两步:1、抹5次水泥 2、砌10块砖;
用线程通信的方式实现。
我们先建一个House的类,里面有两个方法,抹水泥cement()和砌砖brick(),一个工人只能进行一项工作,所以要加同步锁;抹水泥时砌砖等待,抹完后唤醒。
package gemme.thread;
public class TraditionalThreadCommunication {
public static void main(String[] args) {
final Worker worker = new Worker();
/**
* 盖房子要先抹水泥再砌砖,一排砖需要抹5次水泥、砌10块砖
* 现在要垒20排
* */
new Thread() {
@Override
public void run() {
for (int i = 1; i <= 20; i++) {
worker.cement(i);
}
}
}.start();
new Thread() {
@Override
public void run() {
for (int i = 1; i <= 20; i++) {
worker.brick(i);
}
};
}.start();
}
}
class Worker {
private boolean isSub = true;
// 水泥
public synchronized void cement(int loop) {
if (!isSub) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 1; i <= 5; i++) {
System.out.println("cement " + i + " loop of " + loop);
}
isSub = false;
this.notify();
}
// 砌砖
public synchronized void brick(int loop) {
if (isSub) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 1; i <= 10; i++) {
System.out.println("brick " + i + " loop of " + loop);
}
isSub = true;
this.notify();
}
}