异步和多线程区别

同步、异步、多线程、阻塞、非阻塞

同步(sync)-同步阻塞

发出一个功能调用时,在没有得到结果之前,该调用就不返回。

1
2
3
4
5
6
7
8
9
10
11
public class Test {
public static void main(String[] args) {
System.out.println("处理前执行...");
syncProcess();
System.out.println("处理后执行...");
}

private static void syncProcess() {
System.out.println("syncProcess方法");
}
}

执行结果

1
2
3
处理前执行...
synProcess方法
处理后执行...

异步(async)-异步非阻塞

与同步相对,在调用发出之后就直接返回了,可能没有返回结果。对于异步调用,调用的返回并不受调用者控制。

当调用完成后,一般通过状态、通知或回调来通知调用者,具体如下:

状态:调用者监听被调用者的状态(轮询),需要每隔一定时间检查一次,效率低。

通知:当被调用者执行完成后,向调用者发出通知,无需消耗太多性能。

回调:与通知类似,当被调用者执行完成后,调用调用者提供的回调函数。

下面代码若不调用 task.get() 就是多线程。

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
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("处理前执行...");
FutureTask<Integer> task = asyncProcess();
System.out.println("处理后执行...");
System.out.println("处理结果: " + task.get()); // get()使用轮询方式获取被调用者结果
}

private static FutureTask asyncProcess() {
// 从返回值可以看出,使用的构造方法为 public FutureTask(Callable<V> callable)
FutureTask<Integer> task = new FutureTask(() -> {
int i = 1;
while (i <= 5) {
try {
Thread.sleep(1000);
System.out.println("asyncProcess: " + i++);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return --i;
});
new Thread(task).start(); // 使用的构造方法为 public Thread(Runnable target)
return task;
}
}

执行结果

1
2
3
4
5
6
7
8
处理前执行...
处理后执行...
asynProcess: 1
asynProcess: 2
asynProcess: 3
asynProcess: 4
asynProcess: 5
处理结果: 5

多线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("处理前执行...");
multithreading();
System.out.println("处理后执行...");
}

private static void multithreading() {
// 使用的构造方法为 public Thread(Runnable target)
new Thread(() -> {
int i = 1;
while (i <= 5) {
try {
Thread.sleep(1000);
System.out.println("multithreading: " + i++);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}

执行结果

1
2
3
4
5
6
7
处理前执行...
处理后执行...
multithreading: 1
multithreading: 2
multithreading: 3
multithreading: 4
multithreading: 5

多线程和异步区别

多线程关注功能的并发执行,与具体的执行者相关。

异步编程关注函数之间的非阻塞执行,与任务相关,我们可以将异步应用于单线程或多线程当中。

异步和多线程并不是一个同等关系异步是最终目的,多线程只是实现异步的一种手段

实现异步场景(非多线程)

手机验证码登录场景,当我们点击 发送验证码 时,页面立即提示发送成功。

实现

1、接口收到请求后,生成一个六位验证码,将 发送验证码 的任务放到 验证码队列(生产者),返回接口 发送成功

2、验证码消费者负责具体发送功能,同时将此验证码存到redis中的Hash表(key为固定值 SMS_verification_code,field为 手机号,value为 验证码+生成时间)。

3、当用户输入验证码登录调用登录接口时,查询redis中key为固定值 SMS_verification_code,field为 手机号 的value值,有几种情况:

value值 验证value有效期(5分钟) value与用户输入值比较 处理
不存在 —— —— 登录接口返回 msg=”验证码错误”
存在 无效 —— 登录接口返回 msg=”验证码过期,请重新获取!”
存在 有效 不一致 登录接口返回 msg=”验证码错误”
存在 有效 一致 继续登录验证操作

阻塞(block)

阻塞调用:指调用结果返回(或调用者收到通知)之前,当前线程会被挂起,即不继续执行后续操作。

简单来说,等前一件做完了才能做下一件事。

非阻塞(non-block)

非阻塞调用:指在不能立刻得到调用结果的情况下,该调用不会阻塞当前线程。

总结

所以所谓同步异步,是对于被调用者而言的;而阻塞非阻塞,则是对调用者而言的。

加深理解:

1、同步阻塞:你打电话给114查路线,在不挂断的情况下,客服帮你查了十分钟之后告诉你,期间你一直在接听电话。

2、同步非阻塞:你打电话给114查路线,在不挂断的情况下,客服帮你查了十分钟之后告诉你,你期间吃了个🍉(打电话没有影响你做其他事)。

3、异步非阻塞:你打电话给114查路线,客服说查好之后打给你,这期间你可以做任何事。

4、异步阻塞:你打电话给114查路线,客服说查好之后打给你,但这期间你什么都没做,等到回复电话之后,再继续下一步动作。(是不是很傻)现实运用中,多线程获取锁就是异步阻塞