涉及到的知识点:thread.join(), object.wait(), object.notify(), CountdownLatch, CyclicBarrier, FutureTask, Callable 等。
object.wait(), object.notify()
public static void main(String[] args) {
Object obj = new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
System.out.println(Thread.currentThread().getName() +
": 调用wait方法,进入无限等待...");
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
": 嗯,我醒了。");
}
}
}, "等待线程").start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (obj) {
try {
// 让等待线程睡一会儿
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() +
": 醒醒啊,老哥,别睡了!");
obj.notify();
}
}
}, "叫醒线程").start();
}
输出:
等待线程: 调用wait方法,进入无限等待...
叫醒线程: 醒醒啊,老哥,别睡了!
等待线程: 嗯,我醒了。
没有在同步代码块中,就用锁对象(任意对象都可以是锁对象)调用wait方法就会报运行时异常IllegalMonitorStateException
,虽然编译正确(说明方法调用没错误):
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() +
": 调用wait方法,进入无限等待...");
try {
wait(); //IllegalMonitorStateException
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": 嗯,我醒了。");
}
}, "等待线程").start();
利用sleep()方法,令线程休眠时间大于CPU时间片时间实现(效率低):
利用等待唤醒机制实现交替运行:
Thread B print: 1
Thread A print: 1
Thread B print: 2
Thread A print: 2
Thread B print: 3
Thread A print: 3
利用 thread.join() 方法实现线程B等待线程A:
Thread A print: 1
Thread A print: 2
Thread A print: 3
Thread B print: 1
Thread B print: 2
Thread B print: 3
- 利用 object.wait() 和 object.notify() 两个方法来实现线程的中途插入:
Thread A print: 1
Thread B print: 1
Thread B print: 2
Thread B print: 3
Thread A print: 2
Thread A print: 3
利用 CountdownLatch 对象来实现一个线程等待多个线程:
- 创建计数器:CountdownLatch countDownLatch = new CountDownLatch(2);
- 等待线程:调用 countDownLatch.await() 方法;
- 其他线程:调用 countDownLatch.countDown() 方法,该方法会将计数值减小 1;
- 当计数器为 0 时,等待线程 里的 countDownLatch.await() 立即退出,继续执行后面的代码。
利用 CyclicBarrier 对象实现线程之间互相等待
- 创建计数器:CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
- 每个线程准备完毕后,调用 cyclicBarrier.await(),开始等待别人;
- 当指定的 同时等待 的线程数都调用了 cyclicBarrier.await();时,意味着这些线程都准备完毕好,然后这些线程才 同时继续执行。
子线程完成某件任务后(通常比较耗时),把得到的结果回传给主线程。
比如,我们利用子线程去计算从 1 加到 100,并把算出的结果返回到主线程。
Runnable接口中的run() 方法在执行完后不会返回任何结果, Callable接口中的call()方法具有返回值。
利用 Callable 接口和 FutureTask 类实现:
private static void doTaskWithResultInWorker() {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
System.out.println("Task starts");
Thread.sleep(1000);
int result = 0;
for (int i=0; i<=100; i++) {
result += i;
}
System.out.println("Task finished and return result");
return result;
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
try {
System.out.println("Before futureTask.get()");
//FutureTask 中的 get() 方法会阻塞主线程。如果不希望阻塞主线程,
//可以考虑利用 ExecutorService,把 FutureTask 放到线程池去管理执行。
System.out.println("Result:" + futureTask.get());
System.out.println("After futureTask.get()");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
原文链接:wingjay
网友评论