有时候为了满足需求,我们需要在自己的类中进行线程管理/开启线程,并回调我们自己封装好的回调方法。例如:1
2
3
4
5
6
7
8
9
10
11
12
13public void someTask() {
new Thread() {
public void run() {
int n = yourObject.someApi();
onGetResult(n);
}
}.start();
}
private void onGetResult(int result) {
// 处理获取结果
}
在线程任务中调用了某个第三方API,获取到了结果后,我们继续调用封装好的onGetResult
方法。
当第三方API是同步调用时,这个流程很顺畅。但如果这里调用的是异步API,这里就没法直接获取结果了。因此我们需要再封装一层,将此API改成同步阻塞的调用,以便于上层任务调度使用。
例如我们有一个买车票的类TicketHelper
来作为第三方SDK调用,其中买车票的方法是异步实现的: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
27
28
29public class TicketHelper {
// 异步回调监听器
OnBuyTicketListener mListener;
public void setTicketListener(OnBuyTicketListener listener) {
mListener = listener;
}
public void buyTickets(int count) {
new Thread() {
public void run() {
try {
// 模拟异步调用延迟
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 根据车票数量回调
if (count < 0 && mListener != null) {
mListener.ticketFailure("less than zero");
} else if (count > 0 && mListener != null) {
mListener.ticketSuccess("buy ticket success");
}
}
}.start();
}
}
现在我们有一个乘客类,并提供了买车票的方法——直接调用TicketHelper中的买车票api。那么此时我们需要在乘客类中实现一个回调监听器类,或提供一个匿名监听器,我们调用api方法3秒后,会异步的在监听器中拿到结果。1
2
3
4
5
6
7
8
9
10
11public class TicketCustomer {
private TicketHelper helper;
public void testBuyTicket() {
helper.buyTickets(3);
}
class MyTicketListener implements OnBuyTicketListener {
......
}
}
现在我们的需求是将所有TicketCustomer
的动作放入线程队列管理,由任务调度类统一控制,那么此时在线程中调用testBuyTicket
不等结果返回线程就结束了……
为了调用testBuyTicket
后不退出线程,我们引入一个Object充当锁,在testBuyTicket
后进行wait操作。同时在回调函数中进行notify操作,这样我们在wait后添加代码,就可以执行到了,我们可以将回调函数中的参数返回给上一层,这样就达到了同步调用的效果。改造后的代码如下: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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69public class TicketCustomer {
private TicketHelper helper;
private MyTicketListener myListener;
Object obj;
String result;
public TicketCustomer() {
helper = new TicketHelper();
myListener = new MyTicketListener();
helper.setTicketListener(myListener);
obj = new Object();
}
// 异步调用的方法,调用后不会阻塞当前线程,
// 因此"SDK"执行回调方法时,线程可能已经退出了
public void testBuyTicket() {
helper.buyTickets(3);
}
// 同步调用的方法,使用对象锁阻塞住当前线程
public String testBuyTicketSync(int count) {
synchronized (obj) {
helper.buyTickets(count);
try {
// 异步调用就阻塞在这里
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
// notify后继续执行到这里,拿到刚才保存的信息,返回给上层
return result;
}
}
private void onGetMessage(String msg) {
// 此时在另外的线程中,调用notify,使的刚才阻塞状态退出,
// 在退出前我们保存了回调函数的变量
synchronized (obj) {
result = msg;
obj.notify();
}
}
class MyTicketListener implements OnBuyTicketListener {
public void ticketSuccess(String msg) {
// 在回调函数中再调用我们定义的回调函数
onGetMessage(msg);
}
public void ticketFailure(String msg) {
onGetMessage(msg);
}
}
public static void main(String[] args) {
TicketCustomer customer = new TicketCustomer();
String str = customer.testBuyTicketSync(5);
System.out.println(str);
// 主线程在此退出,因此同步的方法可以打印出消息
}
}