-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathRpcInvokerHandler.java
More file actions
184 lines (165 loc) · 5.5 KB
/
Copy pathRpcInvokerHandler.java
File metadata and controls
184 lines (165 loc) · 5.5 KB
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package rpc.framework;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import rpc.framework.connection.IRpcChannel;
import rpc.util.RpcLog;
import rpc.util.RpcTools;
/**
* 使用规范: 不要重用,一旦状态不合法,则直接析构掉。
* 状态判断:调用startup()启动handler,
* 当调用invoke 或者 retieve出现异常的时候,表明出现无法恢复的错误,
* 当出现无法恢复错误时,调用shutdown()关闭handler
* 异常处理:内部有两个独立的线程RecvThread 和 SendThread,当任何一个线程异常时,就会标识 mHasException=true.
* 这时外部调用retrieve 或者 invoke时,就会触发异常。
* @author 23683
*
*/
public class RpcInvokerHandler {
private static final String TAG = "RpcInvokerHandler";
private static final boolean DEBUG = RpcTools.DEBUG;
private BlockingQueue<RpcInvoker> mSendQueue = new LinkedBlockingQueue<RpcInvoker>();
private BlockingQueue<RpcInvoker> mRecvQueue = new LinkedBlockingQueue<RpcInvoker>();
private boolean mHasException = false;
private boolean mIsRunning = false;
IRpcChannel mChannel = null;
private Thread mSendThread = new Thread("SendThread") {
@Override
public void run() {
while(mIsRunning && !mHasException) {
try {
sendInvoker();
} catch (InterruptedException e) {
mHasException = true;
RpcLog.e(TAG, "sendInvoker fail: " + e);
} catch (IOException e) {
mHasException = true;
RpcLog.e(TAG, "sendInvoker fail: " + e);
}
if (mHasException) {
// 防止retrieve时阻塞
addEmptyInvokerToRecvQueue();
}
}
RpcLog.d(TAG, getName() + " is quit");
}
};
private Thread mRecvThread = new Thread("RecvThread") {
@Override
public void run() {
while(mIsRunning && !mHasException) {
try {
receiveInvoker();
} catch (InterruptedException e) {
mHasException = true;
RpcLog.e(TAG, "receiveInvoker fail: " + e);
} catch (IOException e) {
mHasException = true;
RpcLog.e(TAG, "receiveInvoker fail: " + e);
}
if (mHasException) {
// 防止retrieve时阻塞
addEmptyInvokerToRecvQueue();
}
}
RpcLog.d(TAG, getName() + " is quit");
}
};
/**
* 需要考虑避免重入, 直接简单使用synchronized保护
* @param channel
* @return
*/
public synchronized boolean startup() {
if (mIsRunning) { return true; }
RpcLog.d(TAG, "startup");
mIsRunning = true;
mHasException = false;
mSendThread.setDaemon(true);
mSendThread.start();
mRecvThread.setDaemon(true);
mRecvThread.start();
return true;
}
/**
* 需要考虑避免重入, 直接简单使用synchronized保护
* @return
*/
public synchronized boolean shutdown() {
if (!mIsRunning) { return true; }
RpcLog.d(TAG, "shutdown");
mIsRunning = false;
// NOTE::在SendThread和RecvThread之前就close channnel,防止interrupt时遇到IO中断,而无法解除中断
closechannel();
mSendThread.interrupt();
mRecvThread.interrupt();
try {
mSendThread.join();
mRecvThread.join();
} catch (InterruptedException e) {
RpcLog.e(TAG, "Interrupt when wait shutdown." + e);
}
mSendQueue.clear();
mRecvQueue.clear();
addEmptyInvokerToRecvQueue();
return true;
}
private void addEmptyInvokerToRecvQueue() {
try {
// recvqueue添加一个空对象,保证即使handler不再有效了,retrieve仍不会卡住。
mRecvQueue.put(new RpcInvoker(null, null, null));
} catch (InterruptedException e) {
}
}
public boolean isAlive() {
return mIsRunning;
}
/**
* 非阻塞请求。 但如果内部消息缓冲已满,则会阻塞。
* @param invoker
* @return invoker的结果,实际只是一个主动对象,里面的结果还是为null。
* @throws InterruptedException
*/
public RpcInvoker invoke(RpcInvoker invoker) throws InterruptedException {
if (!isAlive()) { throw new InterruptedException("RpcInvokerHandler is dead\n"); }
mSendQueue.put(invoker);
return invoker;
}
/**
*
* @return 当返回InterruptedException异常时,表示handler坏掉了,应该需要shutdownhandler。
* @throws InterruptedException
*/
public RpcInvoker retrieve() throws InterruptedException {
if (!isAlive()) { throw new InterruptedException("RpcInvokerHandler is dead\n"); }
RpcInvoker invoker = mRecvQueue.take();
if (invoker.getId() == -1) {
// 这个表示无效的invoker, 为了发生异常时防止这里堵住,故意推入的。
// 因此,收到这个无效invoker,就意味着handler异常
throw new InterruptedException("RpcInvokerHandler is dead\n");
}
return invoker;
}
private void sendInvoker() throws InterruptedException, IOException {
RpcInvoker invoker = mSendQueue.take();
mChannel.send(invoker);
mSendQueue.remove(invoker);
}
private void receiveInvoker() throws InterruptedException, IOException {
RpcInvoker invoker = mChannel.recv();
if (invoker == null) {
RpcLog.e(TAG, "receive invoker failed");
}
mRecvQueue.put(invoker);
}
public void bindChannel(IRpcChannel channel) {
if (mChannel != null) {
RpcLog.w(TAG, "channel is alreay binded.");
}
mChannel = channel;
}
private void closechannel() {
mChannel.close();
// mChannel = null; //无需重置,避免空指针错误
}
}