正常环境下,每个子线程完成各自的任务就可以竣事了。不外有的时候,我们但愿多个线程协同事情来完成某个任务,这时就涉及到了线程间通信了。
本文涉及到的常识点:thread.join(), object.wait(), object.notify(), CountdownLatch, CyclicBarrier, FutureTask, Callable 等。
本文涉及代码:
https://github.com/wingjay/HelloJava/blob/master/multi-thread/src/ForArticle.java
下面我从几个例子作为切入点来讲授下 Java 里有哪些要领来实现线程间通信。
如何让两个线程依次执行?
假设有两个线程,一个是线程 A,另一个是线程 B,两个线程别离依次打印 1-3 三个数字即可。我们来看下代码:
java; gutter: true">private static void demo1() {
Thread A = new Thread(new Runnable() {
@Override
public void run() {
printNumber("A");
}
});
Thread B = new Thread(new Runnable() {
@Override
public void run() {
printNumber("B");
}
});
A.start();
B.start();
}
个中的 printNumber(String) 实现如下,用来依次打印 1, 2, 3 三个数字:
private static void printNumber(String threadName) {
int i=0;
while (i++ < 3) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(threadName + "print:" + i);
}
}
这时我们获得的功效是:
B print: 1 A print: 1 B print: 2 A print: 2 B print: 3 A print: 3
可以看到 A 和 B 是同时打印的。
那么,假如我们但愿 B 在 A 全部打印 完后再开始打印呢?我们可以操作 thread.join() 要领,代码如下:
private static void demo2() {
Thread A = new Thread(new Runnable() {
@Override
public void run() {
printNumber("A");
}
});
Thread B = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("B 开始期待 A");
try {
A.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
printNumber("B");
}
});
B.start();
A.start();
}
获得的功效如下:
B 开始期待 A A print: 1 A print: 2 A print: 3 B print: 1 B print: 2 B print: 3
所以我们能看到 A.join() 要了解让 B 一直期待直到 A 运行完毕。
那如何让 两个线程凭据指定方法有序交错运行呢?
照旧上面谁人例子,我此刻但愿 A 在打印完 1 后,再让 B 打印 1, 2, 3,最后再回到 A 继承打印 2, 3。这种需求下,显然 Thread.join() 已经不能满意了。我们需要更细粒度的锁来节制执行顺序。
这里,我们可以操作 object.wait() 和 object.notify() 两个要领来实现。代码如下:
/**
* A 1, B 1, B 2, B 3, A 2, A 3
*/
private static void demo3() {
Object lock = new Object();
Thread A = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println("A 1");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("A 2");
System.out.println("A 3");
}
}
});
Thread B = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock) {
System.out.println("B 1");
System.out.println("B 2");
System.out.println("B 3");
lock.notify();
}
}
});
A.start();
B.start();
}
打印功效如下:
A 1 A waiting… B 1 B 2 B 3 A 2 A 3
正是我们要的功效。
那么,这个进程产生了什么呢?