文章目录
往期
同步与异步
以调用方角度来讲,如果
- 需要等待结果返回,才能继续运行就是同步
- 不需要等待结果返回,就能继续运行就是异步
需要等待结果
这时既可以使用同步处理,也可以使用异步来处理
1. join实现(同步)
static int result = 0;
private static void test1() throws InterruptedException {
log.debug("开始");
Thread t1 = new Thread(() -> {
log.debug("开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("结束");
result = 10;
}, "t1");
t1.start();
t1.join();
log.debug("结果为:{}", result);
}
输出
19:46:36.178 [main] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
19:46:36.272 [t1] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
19:46:37.294 [t1] DEBUG SyncAndAsync.TestSyncAndAsync - 结束
19:46:37.294 [main] DEBUG SyncAndAsync.TestSyncAndAsync - 结果为:10
评价
- 需要外部共享变量,不符合面向对象封装的思想
- 必须等待线程结束,不能配合线程池使用
2. Future实现(同步)
private static void test2() throws InterruptedException, ExecutionException {
log.debug("开始");
FutureTask<Integer> result = new FutureTask<>(() -> {
log.debug("开始");
Thread.sleep(1000);
log.debug("结束");
return 10;
});
new Thread(result, "t1").start();
log.debug("结果为:{}", result.get());
}
输出
19:48:19.840 [main] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
19:48:19.933 [t1] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
19:48:20.934 [t1] DEBUG SyncAndAsync.TestSyncAndAsync - 结束
19:48:20.935 [main] DEBUG SyncAndAsync.TestSyncAndAsync - 结果为:10
评价
- 规避了使用join之前的缺点
- 可以方便配合线程池使用
private static void test3() throws ExecutionException, InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(1);
log.debug("开始");
Future<Integer> result = service.submit(()->{
log.debug("开始");
Thread.sleep(1000);
log.debug("结束");
return 10;
});
log.debug("结果:{},result的类型:{}",result.get(), result.getClass());
service.shutdown();
}
输出
19:53:07.072 [main] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
19:53:07.177 [pool-1-thread-1] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
19:53:08.177 [pool-1-thread-1] DEBUG SyncAndAsync.TestSyncAndAsync - 结束
19:53:08.177 [main] DEBUG SyncAndAsync.TestSyncAndAsync - 结果:10,result的类型:class java.util.concurrent.FutureTask
评价
- 仍然是main线程接收结果
- get方法是让调用线程同步等待
3. 自定义实现-保护性暂停(同步)
- 定义
即 Guarded Suspension, 用在一个线程等待另一个线程的执行结果
要点
- 有一个结果需要从一个线程传递到另一个线程,让他们关联同一个 GuardedObject
- 如果有结果不断从一个线程到另一个线程那么可以使用消息队列(见生产者/消费者)
- JDK中,join的实现、Future的实现,采用的就是此模式
- 因为要等待另一方的结果,因此归类到同步模式
- 实现(带超时版)
class GuardedObject{
// 结果
private Object response;
private static final Logger log = LoggerFactory.getLogger(GuardedObject.class);
// 获取结果
// timeout 表示要等待多久
public Object getResponse(long timeout) throws InterruptedException {
synchronized (this) {
// 开始时间
long begin = System.currentTimeMillis();
// 经历时间
long passedTime = 0;
// 没有结果
while (response == null) {
long waitTime = timeout - passedTime; // 这一轮循环应该等待的时间
// 经历的时间超过了最大等待时间就退出循环
if (waitTime <= 0) {
break;
}
this.wait(waitTime);
passedTime = System.currentTimeMillis() - begin;
log.debug("timePassed:{}, object is null {}", passedTime, response == null);
}
return response;
}
}
// 产生结果
public void setResponse(Object response) {
synchronized (this) {
// 给结果成员变量赋值
this.response = response;
this.notifyAll();
}
}
}
应用:一个线程等待另一个线程的执行结果
public class Downloader {
public static List<String> download() throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL("https://www.baidu.com/").openConnection();
List<String> lines = new ArrayList<>();
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
String line;
while ((line =reader.readLine()) != null) {
lines.add(line);
}
}
return lines;
}
}
public static void main(String[] args) {
test1();
}
public static void test1() {
// t1等待t2 的下载结果
final GuardedObject guardedObject = new GuardedObject();
new Thread(()->{
// 等待结果
log.debug("等待结果");
try {
List<String> response = (List<String>)guardedObject.getResponse(2000);
log.debug("结果大小:{}",response.size());
//log.debug("{}",response);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
log.debug("执行下载");
try {
List<String> list = Downloader.download();
guardedObject.setResponse(list);
} catch (IOException e) {
e.printStackTrace();
}
}, "t2").start();
}
执行结果
20:32:14.327 [t2] DEBUG Share.GuardedSuspension4_8.TestGuardSuspension - 执行下载
20:32:14.327 [t1] DEBUG Share.GuardedSuspension4_8.TestGuardSuspension - 等待结果
20:32:15.332 [t1] DEBUG Share.GuardedSuspension4_8.GuardedObject - timePassed:1000, object is null false
20:32:15.335 [t1] DEBUG Share.GuardedSuspension4_8.TestGuardSuspension - 结果大小:3
4. CompletableFuture实现(异步)
private static void test4() {
// 进行计算的线程池
ExecutorService computeService = Executors.newFixedThreadPool(1);
// 接收结果的线程池
ExecutorService resultService = Executors.newFixedThreadPool(1);
log.debug("开始");
CompletableFuture.supplyAsync(() -> {
log.debug("开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("结束");
return 10;
}, computeService).thenAcceptAsync((result) -> {
log.debug("结果为:{}", result);
}, resultService);
}
输出
20:36:46.292 [main] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
20:36:46.392 [pool-1-thread-1] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
20:36:47.408 [pool-1-thread-1] DEBUG SyncAndAsync.TestSyncAndAsync - 结束
20:36:47.409 [pool-2-thread-1] DEBUG SyncAndAsync.TestSyncAndAsync - 结果为:10
评价
- 可以让调用线程异步处理结果,实际是其他线程去同步等待
- 可以方便地分离不同职责的线程池
- 以任务为中心,而不是以线程为中心
5. BlockingQueue实现(异步)
private static void test5() {
ExecutorService consumer = Executors.newFixedThreadPool(1);
ExecutorService producer = Executors.newFixedThreadPool(1);
SynchronousQueue<Integer> queue = new SynchronousQueue<>();
log.debug("开始");
producer.submit(()->{
log.debug("开始");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("结束");
try {
queue.put(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
consumer.submit(()->{
Integer res = null;
try {
res = queue.take();
log.debug("结果为:{}",res);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
consumer.shutdown();
producer.shutdown();
}
输出结果
20:45:42.931 [main] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
20:45:43.018 [pool-2-thread-1] DEBUG SyncAndAsync.TestSyncAndAsync - 开始
20:45:44.018 [pool-2-thread-1] DEBUG SyncAndAsync.TestSyncAndAsync - 结束
20:45:44.018 [pool-1-thread-1] DEBUG SyncAndAsync.TestSyncAndAsync - 结果为:10