getClientMap() {
42 | return clientMap;
43 | }
44 |
45 | public static final String DEFAULT_WEBSOCKET = "DEFAULT_WEBSOCKET";
46 | public static final String NO_INIT = "没有初始化";
47 |
48 | private WebSocketServer webSocketServer;
49 |
50 | private ConnectivityManager connectivityManager;
51 | private ConnectivityManager.NetworkCallback networkCallback;
52 | private boolean isNetworkAvailable;
53 |
54 | private boolean isReconnectTaskRun = false;
55 |
56 | private int attempt = 0;
57 |
58 | private AtomicInteger taskReconnectCount = new AtomicInteger(0);
59 |
60 | private ReconnectGuardianTask guardianTask;
61 |
62 | /**
63 | * 重连保护进程的间隔,单位秒,默认60
64 | */
65 | private int guardianTaskInterval = 60;
66 |
67 | /**
68 | * 设置重连保护的间隔并启动保护任务
69 | *
70 | * @param guardianTaskInterval 保护检测间隔,单位秒,要求大于0且大于【2* reconnectCount * reconnectInterval】
71 | */
72 | public void startGuardianTaskInterval(int guardianTaskInterval) {
73 | this.guardianTaskInterval = guardianTaskInterval;
74 | ThreadUtils.cancel(guardianTask);
75 | guardianTask = new ReconnectGuardianTask();
76 | guardianTask.execute();
77 |
78 | }
79 |
80 | public int getGuardianTaskInterval() {
81 | return guardianTaskInterval;
82 | }
83 |
84 | public WebSocketServer getWebSocketServer() {
85 | return webSocketServer;
86 | }
87 |
88 | public synchronized void startWsServer(InetSocketAddress address, IWebSocketServerListener listener) {
89 | attempt = 0;
90 | webSocketServer = new WebSocketServer(address) {
91 | @Override
92 | public void onOpen(WebSocket conn, ClientHandshake handshake) {
93 | listener.onWsOpen(conn, handshake);
94 | }
95 |
96 | @Override
97 | public void onClose(WebSocket conn, int code, String reason, boolean remote) {
98 | listener.onWsClose(conn, code, reason, remote);
99 | }
100 |
101 | @Override
102 | public void onMessage(WebSocket conn, String message) {
103 | listener.onWsMessage(conn, message);
104 | }
105 |
106 | @Override
107 | public void onError(WebSocket conn, Exception ex) {
108 | if (ex instanceof BindException) {
109 | attempt++;
110 | WsLogUtil.e("端口被占用, 尝试端口:" + (address.getPort() + attempt));
111 | }
112 | listener.onWsError(conn, ex);
113 | }
114 |
115 | @Override
116 | public void onStart() {
117 | listener.onWsStart(webSocketServer);
118 | }
119 | };
120 | webSocketServer.setReuseAddr(true);
121 | webSocketServer.start();
122 | // 添加JVM关闭钩子,当应用退出时,关闭WebSocket服务
123 | Runtime.getRuntime().addShutdownHook(new Thread(() -> WsManager.getInstance().stopWsServer()));
124 | }
125 |
126 | public synchronized void stopWsServer() {
127 | if (webSocketServer != null) {
128 | try {
129 | webSocketServer.stop();
130 | } catch (InterruptedException e) {
131 | WsLogUtil.e(e.getMessage());
132 | }
133 | webSocketServer = null;
134 | }
135 | }
136 |
137 | /**
138 | * 设置重连次数
139 | */
140 | public void setTaskReconnectCount(int taskReconnectCount) {
141 | this.taskReconnectCount = new AtomicInteger(taskReconnectCount);
142 | }
143 |
144 | /**
145 | * 获取重连次数
146 | */
147 | public int getTaskReconnectCount() {
148 | return taskReconnectCount.get();
149 | }
150 |
151 | /**
152 | * 重置重连次数
153 | */
154 | public synchronized void resetTaskReconnectCount() {
155 | taskReconnectCount = new AtomicInteger(0);
156 | }
157 |
158 | public synchronized void setReconnectTaskRun(boolean reconnectTaskRun) {
159 | isReconnectTaskRun = reconnectTaskRun;
160 | }
161 |
162 | public synchronized boolean isReconnectTaskRun() {
163 | return isReconnectTaskRun;
164 | }
165 |
166 | /**
167 | * 获取连接池中最大的连接次数
168 | */
169 | public int getMaxReconnectCount() {
170 | int tempCount = 0;
171 | for (WsClient ws : clientMap.values()) {
172 | if (ws.getReconnectCount() > tempCount) {
173 | tempCount = ws.getReconnectCount();
174 | }
175 | }
176 | return tempCount;
177 | }
178 |
179 | public long getMaxReconnectInterval() {
180 | long tempInterval = 0;
181 | for (WsClient ws : clientMap.values()) {
182 | if (ws.getReconnectInterval() > tempInterval) {
183 | tempInterval = ws.getReconnectInterval();
184 | }
185 | }
186 | return tempInterval;
187 | }
188 |
189 | public WsManager() {
190 | }
191 |
192 | public static WsManager getInstance() {
193 | return SingletonHelper.INSTANCE;
194 | }
195 |
196 | private static class SingletonHelper {
197 | private final static WsManager INSTANCE = new WsManager();
198 | }
199 |
200 | public boolean isNetworkAvailable() {
201 | return isNetworkAvailable;
202 | }
203 |
204 | public void updateNetworkAvailable(Network network) {
205 | NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(network);
206 | isNetworkAvailable = networkCapabilities != null && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
207 | }
208 |
209 | /**
210 | * 注册网络变化监听广播,网络由不可用变为可用时会重新连接 WebSocket
211 | * 调用后会立即触发一次OnReceive
212 | */
213 | public void registerNetworkChangedCallback() {
214 | if (networkCallback != null) {
215 | WsLogUtil.e("网络状态监听已注册");
216 | return;
217 | }
218 | if (!checkPermission()) {
219 | WsLogUtil.e("未获取到网络状态权限,广播监听器无法注册");
220 | return;
221 | }
222 | connectivityManager = (ConnectivityManager) AppUtils
223 | .getInstance()
224 | .getApp()
225 | .getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
226 | NetworkRequest.Builder builder = new NetworkRequest.Builder();
227 | networkCallback = new ConnectivityManager.NetworkCallback() {
228 | @Override
229 | public void onAvailable(@NonNull Network network) {
230 | updateNetworkAvailable(network);
231 | for (WsClient ws : WsManager.getInstance().getClientMap().values()) {
232 | if (ws.isReConnectWhenNetworkAvailable() && !ws.isOpen() && !WsManager.getInstance().isReconnectTaskRun()) {
233 | ws.runReconnectTask();
234 | }
235 | }
236 | WsLogUtil.e("网络状态:" + isNetworkAvailable);
237 | }
238 |
239 | @Override
240 | public void onLost(@NonNull Network network) {
241 | updateNetworkAvailable(network);
242 | WsLogUtil.e("网络状态:" + isNetworkAvailable);
243 | }
244 | };
245 | connectivityManager.registerNetworkCallback(builder.build(), networkCallback);
246 | // 添加JVM关闭钩子,当应用退出时,关闭WebSocket服务
247 | Runtime.getRuntime().addShutdownHook(new Thread(() -> WsManager.getInstance().destroy()));
248 | }
249 |
250 | /**
251 | * 解除网络状态广播
252 | */
253 | private void unRegisterNetworkChangedCallback() {
254 | if (networkCallback == null) {
255 | WsLogUtil.d("网络状态广播未注册");
256 | return;
257 | }
258 | connectivityManager.unregisterNetworkCallback(networkCallback);
259 | networkCallback = null;
260 | }
261 |
262 | /**
263 | * 判断是否有网络权限{@link Manifest.permission#ACCESS_NETWORK_STATE}
264 | */
265 | private boolean checkPermission() {
266 | Context context = AppUtils.getInstance().getApp().getApplicationContext();
267 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
268 | return PackageManager.PERMISSION_GRANTED == context.getPackageManager()
269 | .checkPermission(ACCESS_NETWORK_STATE, context.getPackageName());
270 | }
271 | return true;
272 | }
273 |
274 | private void addClient(WsClient wsClient) {
275 | // 移除旧的WebSocket,再重新添加
276 | if (clientMap.containsKey(wsClient.getWsKey())) {
277 | WsClient oldClient = clientMap.get(wsClient.getWsKey());
278 | if (oldClient != null) {
279 | oldClient.closeConnection(-1, "addClient, close old");
280 | } else {
281 | WsLogUtil.e("Tried to close old connection, but it was null");
282 | }
283 | }
284 | clientMap.put(wsClient.getWsKey(), wsClient);
285 | }
286 |
287 | /**
288 | * 是否关闭日志输出,默认开启
289 | *
290 | * @param isClose 是否关闭
291 | */
292 | public WsManager closeLog(boolean isClose) {
293 | WsLogUtil.closeLog(isClose);
294 | return this;
295 | }
296 |
297 | /**
298 | * 获取默认的WebSocket
299 | */
300 | public WsManager init(WsClient wsClient) {
301 | addClient(wsClient);
302 | return this;
303 | }
304 |
305 | /**
306 | * 开始执行连接,每个WebSocket都会创建对应的重连任务
307 | */
308 | public void start() {
309 | registerNetworkChangedCallback();
310 | try {
311 | for (WsClient ws : clientMap.values()) {
312 | if (ws.isOpen()) {
313 | WsLogUtil.e("请勿重复连接, key = " + ws.getWsKey());
314 | continue;
315 | }
316 | if (ws.isClosed()) {
317 | ws = reCreateClient(ws);
318 | clientMap.put(ws.getWsKey(), ws);
319 | ws.connect();
320 | } else {
321 | ws.connectBlocking();
322 | }
323 | }
324 | } catch (Exception e) {
325 | WsLogUtil.e(e.getMessage());
326 | }
327 | }
328 |
329 | public void safeConnect(WsClient ws) {
330 | if (ws.isOpen()) {
331 | WsLogUtil.e("请勿重复连接, key = " + ws.getWsKey());
332 | return;
333 | }
334 | if (ws.isClosed()) {
335 | ws = reCreateClient(ws);
336 | clientMap.put(ws.getWsKey(), ws);
337 | }
338 | try {
339 | ws.connect();
340 | } catch (IllegalStateException e) {
341 | if (e.getMessage() != null && e.getMessage().contains("WebSocketClient objects are not reuseable")) {
342 | ws = reCreateClient(ws);
343 | clientMap.put(ws.getWsKey(), ws);
344 | ws.connect();
345 | }
346 | } catch (Exception e) {
347 | WsLogUtil.e(e.getMessage());
348 | }
349 | }
350 |
351 | private WsClient reCreateClient(WsClient oldWsClient) {
352 | return new WsClient.Builder()
353 | .setServerUrl(oldWsClient.getServerUrl())
354 | .setWsKey(oldWsClient.getWsKey())
355 | .setPingInterval(oldWsClient.getPingInterval())
356 | .setDraft(oldWsClient.getDraft())
357 | .setHttpHeaders(oldWsClient.getHttpHeaders())
358 | .setConnectTimeout(oldWsClient.getConnectTimeout())
359 | .setReconnectCount(oldWsClient.getReconnectCount())
360 | .setReconnectInterval(oldWsClient.getReconnectInterval())
361 | .setReConnectWhenNetworkAvailable(oldWsClient.isReConnectWhenNetworkAvailable())
362 | .setListener(oldWsClient.getListener())
363 | .build();
364 | }
365 |
366 | public WsClient getDefault() {
367 | return getWsClient(DEFAULT_WEBSOCKET);
368 | }
369 |
370 | public WsClient getWsClient(String wsKey) {
371 | if (!clientMap.containsKey(wsKey)) {
372 | WsLogUtil.e(NO_INIT + wsKey);
373 | return null;
374 | }
375 | return clientMap.get(wsKey);
376 | }
377 |
378 | /**
379 | * 使用默认WebSocket发送信息
380 | *
381 | * @param message 消息
382 | */
383 | public void send(String message) {
384 | send(DEFAULT_WEBSOCKET, message);
385 | }
386 |
387 | /**
388 | * 使用指定的WebSocket发送信息
389 | *
390 | * @param wsKey webSocket Key
391 | * @param message 消息
392 | */
393 | public void send(String wsKey, String message) {
394 | getWsClient(wsKey).send(message);
395 | }
396 |
397 | /**
398 | * 使用默认WebSocket发送ping
399 | */
400 | public void sendPing() {
401 | send(DEFAULT_WEBSOCKET);
402 | }
403 |
404 | /**
405 | * 使用指定的WebSocket发送ping
406 | *
407 | * @param wsKey webSocket Key
408 | */
409 | public void sendPing(String wsKey) {
410 | getWsClient(wsKey).sendPing();
411 | }
412 |
413 | /**
414 | * @return 默认WebSocket是否连接
415 | */
416 | public boolean isConnected() {
417 | if (getDefault() == null) {
418 | return false;
419 | }
420 | return isConnected(DEFAULT_WEBSOCKET);
421 | }
422 |
423 | /**
424 | * @param wsKey wsKey
425 | * @return WebSocket是否连接
426 | */
427 | public boolean isConnected(String wsKey) {
428 | if (getWsClient(wsKey) == null) {
429 | return false;
430 | }
431 | return getWsClient(wsKey).isOpen();
432 | }
433 |
434 | /**
435 | * 断开默认WebSocket连接
436 | */
437 | public void disConnect() {
438 | disConnect(DEFAULT_WEBSOCKET);
439 | }
440 |
441 | /**
442 | * 断开指定WebSocket
443 | *
444 | * @param wsKey wsKey
445 | */
446 | public void disConnect(String wsKey) {
447 | getWsClient(wsKey).close();
448 | }
449 |
450 | /**
451 | * 销毁资源, 销毁后Websocket需要重新初始化
452 | */
453 | public void destroy() {
454 | // 解除广播
455 | unRegisterNetworkChangedCallback();
456 | if (webSocketServer != null){
457 | webSocketServer = null;
458 | }
459 | // 关闭连接
460 | for (WsClient ws : clientMap.values()) {
461 | if (!ws.isFlushAndClose()) {
462 | ws.closeConnection(-1, "destroy");
463 | }
464 | }
465 | clientMap.clear();
466 | }
467 |
468 | }
469 |
--------------------------------------------------------------------------------
/websocketlib/src/main/java/com/eurigo/websocketlib/util/ThreadUtils.java:
--------------------------------------------------------------------------------
1 | package com.eurigo.websocketlib.util;
2 |
3 | import android.os.Handler;
4 | import android.os.Looper;
5 | import android.util.Log;
6 |
7 | import androidx.annotation.CallSuper;
8 | import androidx.annotation.IntRange;
9 | import androidx.annotation.NonNull;
10 |
11 | import java.util.HashMap;
12 | import java.util.List;
13 | import java.util.Map;
14 | import java.util.Timer;
15 | import java.util.TimerTask;
16 | import java.util.concurrent.ConcurrentHashMap;
17 | import java.util.concurrent.CountDownLatch;
18 | import java.util.concurrent.Executor;
19 | import java.util.concurrent.ExecutorService;
20 | import java.util.concurrent.LinkedBlockingQueue;
21 | import java.util.concurrent.RejectedExecutionException;
22 | import java.util.concurrent.ThreadFactory;
23 | import java.util.concurrent.ThreadPoolExecutor;
24 | import java.util.concurrent.TimeUnit;
25 | import java.util.concurrent.atomic.AtomicBoolean;
26 | import java.util.concurrent.atomic.AtomicInteger;
27 | import java.util.concurrent.atomic.AtomicLong;
28 |
29 | /**
30 | *
31 | * author: Blankj
32 | * blog : http://blankj.com
33 | * time : 2018/05/08
34 | * desc : utils about thread
35 | *
36 | */
37 | public final class ThreadUtils {
38 |
39 | private static final Handler HANDLER = new Handler(Looper.getMainLooper());
40 |
41 | private static final Map> TYPE_PRIORITY_POOLS = new HashMap<>();
42 |
43 | private static final Map TASK_POOL_MAP = new ConcurrentHashMap<>();
44 |
45 | private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
46 | private static final Timer TIMER = new Timer();
47 |
48 | private static final byte TYPE_SINGLE = -1;
49 | private static final byte TYPE_CACHED = -2;
50 | private static final byte TYPE_IO = -4;
51 | private static final byte TYPE_CPU = -8;
52 |
53 | private static Executor sDeliver;
54 |
55 | /**
56 | * Return whether the thread is the main thread.
57 | *
58 | * @return {@code true}: yes
{@code false}: no
59 | */
60 | public static boolean isMainThread() {
61 | return Looper.myLooper() == Looper.getMainLooper();
62 | }
63 |
64 | public static Handler getMainHandler() {
65 | return HANDLER;
66 | }
67 |
68 | public static void runOnUiThread(final Runnable runnable) {
69 | if (Looper.myLooper() == Looper.getMainLooper()) {
70 | runnable.run();
71 | } else {
72 | HANDLER.post(runnable);
73 | }
74 | }
75 |
76 | public static void runOnUiThreadDelayed(final Runnable runnable, long delayMillis) {
77 | HANDLER.postDelayed(runnable, delayMillis);
78 | }
79 |
80 | /**
81 | * Return a thread pool that reuses a fixed number of threads
82 | * operating off a shared unbounded queue, using the provided
83 | * ThreadFactory to create new threads when needed.
84 | *
85 | * @param size The size of thread in the pool.
86 | * @return a fixed thread pool
87 | */
88 | public static ExecutorService getFixedPool(@IntRange(from = 1) final int size) {
89 | return getPoolByTypeAndPriority(size);
90 | }
91 |
92 | /**
93 | * Return a thread pool that reuses a fixed number of threads
94 | * operating off a shared unbounded queue, using the provided
95 | * ThreadFactory to create new threads when needed.
96 | *
97 | * @param size The size of thread in the pool.
98 | * @param priority The priority of thread in the poll.
99 | * @return a fixed thread pool
100 | */
101 | public static ExecutorService getFixedPool(@IntRange(from = 1) final int size,
102 | @IntRange(from = 1, to = 10) final int priority) {
103 | return getPoolByTypeAndPriority(size, priority);
104 | }
105 |
106 | /**
107 | * Return a thread pool that uses a single worker thread operating
108 | * off an unbounded queue, and uses the provided ThreadFactory to
109 | * create a new thread when needed.
110 | *
111 | * @return a single thread pool
112 | */
113 | public static ExecutorService getSinglePool() {
114 | return getPoolByTypeAndPriority(TYPE_SINGLE);
115 | }
116 |
117 | /**
118 | * Return a thread pool that uses a single worker thread operating
119 | * off an unbounded queue, and uses the provided ThreadFactory to
120 | * create a new thread when needed.
121 | *
122 | * @param priority The priority of thread in the poll.
123 | * @return a single thread pool
124 | */
125 | public static ExecutorService getSinglePool(@IntRange(from = 1, to = 10) final int priority) {
126 | return getPoolByTypeAndPriority(TYPE_SINGLE, priority);
127 | }
128 |
129 | /**
130 | * Return a thread pool that creates new threads as needed, but
131 | * will reuse previously constructed threads when they are
132 | * available.
133 | *
134 | * @return a cached thread pool
135 | */
136 | public static ExecutorService getCachedPool() {
137 | return getPoolByTypeAndPriority(TYPE_CACHED);
138 | }
139 |
140 | /**
141 | * Return a thread pool that creates new threads as needed, but
142 | * will reuse previously constructed threads when they are
143 | * available.
144 | *
145 | * @param priority The priority of thread in the poll.
146 | * @return a cached thread pool
147 | */
148 | public static ExecutorService getCachedPool(@IntRange(from = 1, to = 10) final int priority) {
149 | return getPoolByTypeAndPriority(TYPE_CACHED, priority);
150 | }
151 |
152 | /**
153 | * Return a thread pool that creates (2 * CPU_COUNT + 1) threads
154 | * operating off a queue which size is 128.
155 | *
156 | * @return a IO thread pool
157 | */
158 | public static ExecutorService getIoPool() {
159 | return getPoolByTypeAndPriority(TYPE_IO);
160 | }
161 |
162 | /**
163 | * Return a thread pool that creates (2 * CPU_COUNT + 1) threads
164 | * operating off a queue which size is 128.
165 | *
166 | * @param priority The priority of thread in the poll.
167 | * @return a IO thread pool
168 | */
169 | public static ExecutorService getIoPool(@IntRange(from = 1, to = 10) final int priority) {
170 | return getPoolByTypeAndPriority(TYPE_IO, priority);
171 | }
172 |
173 | /**
174 | * Return a thread pool that creates (CPU_COUNT + 1) threads
175 | * operating off a queue which size is 128 and the maximum
176 | * number of threads equals (2 * CPU_COUNT + 1).
177 | *
178 | * @return a cpu thread pool for
179 | */
180 | public static ExecutorService getCpuPool() {
181 | return getPoolByTypeAndPriority(TYPE_CPU);
182 | }
183 |
184 | /**
185 | * Return a thread pool that creates (CPU_COUNT + 1) threads
186 | * operating off a queue which size is 128 and the maximum
187 | * number of threads equals (2 * CPU_COUNT + 1).
188 | *
189 | * @param priority The priority of thread in the poll.
190 | * @return a cpu thread pool for
191 | */
192 | public static ExecutorService getCpuPool(@IntRange(from = 1, to = 10) final int priority) {
193 | return getPoolByTypeAndPriority(TYPE_CPU, priority);
194 | }
195 |
196 | /**
197 | * Executes the given task in a fixed thread pool.
198 | *
199 | * @param size The size of thread in the fixed thread pool.
200 | * @param task The task to execute.
201 | * @param The type of the task's result.
202 | */
203 | public static void executeByFixed(@IntRange(from = 1) final int size, final Task task) {
204 | execute(getPoolByTypeAndPriority(size), task);
205 | }
206 |
207 | /**
208 | * Executes the given task in a fixed thread pool.
209 | *
210 | * @param size The size of thread in the fixed thread pool.
211 | * @param task The task to execute.
212 | * @param priority The priority of thread in the poll.
213 | * @param The type of the task's result.
214 | */
215 | public static void executeByFixed(@IntRange(from = 1) final int size,
216 | final Task task,
217 | @IntRange(from = 1, to = 10) final int priority) {
218 | execute(getPoolByTypeAndPriority(size, priority), task);
219 | }
220 |
221 | /**
222 | * Executes the given task in a fixed thread pool after the given delay.
223 | *
224 | * @param size The size of thread in the fixed thread pool.
225 | * @param task The task to execute.
226 | * @param delay The time from now to delay execution.
227 | * @param unit The time unit of the delay parameter.
228 | * @param The type of the task's result.
229 | */
230 | public static void executeByFixedWithDelay(@IntRange(from = 1) final int size,
231 | final Task task,
232 | final long delay,
233 | final TimeUnit unit) {
234 | executeWithDelay(getPoolByTypeAndPriority(size), task, delay, unit);
235 | }
236 |
237 | /**
238 | * Executes the given task in a fixed thread pool after the given delay.
239 | *
240 | * @param size The size of thread in the fixed thread pool.
241 | * @param task The task to execute.
242 | * @param delay The time from now to delay execution.
243 | * @param unit The time unit of the delay parameter.
244 | * @param priority The priority of thread in the poll.
245 | * @param The type of the task's result.
246 | */
247 | public static void executeByFixedWithDelay(@IntRange(from = 1) final int size,
248 | final Task task,
249 | final long delay,
250 | final TimeUnit unit,
251 | @IntRange(from = 1, to = 10) final int priority) {
252 | executeWithDelay(getPoolByTypeAndPriority(size, priority), task, delay, unit);
253 | }
254 |
255 | /**
256 | * Executes the given task in a fixed thread pool at fix rate.
257 | *
258 | * @param size The size of thread in the fixed thread pool.
259 | * @param task The task to execute.
260 | * @param period The period between successive executions.
261 | * @param unit The time unit of the period parameter.
262 | * @param The type of the task's result.
263 | */
264 | public static void executeByFixedAtFixRate(@IntRange(from = 1) final int size,
265 | final Task task,
266 | final long period,
267 | final TimeUnit unit) {
268 | executeAtFixedRate(getPoolByTypeAndPriority(size), task, 0, period, unit);
269 | }
270 |
271 | /**
272 | * Executes the given task in a fixed thread pool at fix rate.
273 | *
274 | * @param size The size of thread in the fixed thread pool.
275 | * @param task The task to execute.
276 | * @param period The period between successive executions.
277 | * @param unit The time unit of the period parameter.
278 | * @param priority The priority of thread in the poll.
279 | * @param The type of the task's result.
280 | */
281 | public static void executeByFixedAtFixRate(@IntRange(from = 1) final int size,
282 | final Task task,
283 | final long period,
284 | final TimeUnit unit,
285 | @IntRange(from = 1, to = 10) final int priority) {
286 | executeAtFixedRate(getPoolByTypeAndPriority(size, priority), task, 0, period, unit);
287 | }
288 |
289 | /**
290 | * Executes the given task in a fixed thread pool at fix rate.
291 | *
292 | * @param size The size of thread in the fixed thread pool.
293 | * @param task The task to execute.
294 | * @param initialDelay The time to delay first execution.
295 | * @param period The period between successive executions.
296 | * @param unit The time unit of the initialDelay and period parameters.
297 | * @param The type of the task's result.
298 | */
299 | public static void executeByFixedAtFixRate(@IntRange(from = 1) final int size,
300 | final Task task,
301 | long initialDelay,
302 | final long period,
303 | final TimeUnit unit) {
304 | executeAtFixedRate(getPoolByTypeAndPriority(size), task, initialDelay, period, unit);
305 | }
306 |
307 | /**
308 | * Executes the given task in a fixed thread pool at fix rate.
309 | *
310 | * @param size The size of thread in the fixed thread pool.
311 | * @param task The task to execute.
312 | * @param initialDelay The time to delay first execution.
313 | * @param period The period between successive executions.
314 | * @param unit The time unit of the initialDelay and period parameters.
315 | * @param priority The priority of thread in the poll.
316 | * @param The type of the task's result.
317 | */
318 | public static void executeByFixedAtFixRate(@IntRange(from = 1) final int size,
319 | final Task task,
320 | long initialDelay,
321 | final long period,
322 | final TimeUnit unit,
323 | @IntRange(from = 1, to = 10) final int priority) {
324 | executeAtFixedRate(getPoolByTypeAndPriority(size, priority), task, initialDelay, period, unit);
325 | }
326 |
327 | /**
328 | * Executes the given task in a single thread pool.
329 | *
330 | * @param task The task to execute.
331 | * @param The type of the task's result.
332 | */
333 | public static void executeBySingle(final Task task) {
334 | execute(getPoolByTypeAndPriority(TYPE_SINGLE), task);
335 | }
336 |
337 | /**
338 | * Executes the given task in a single thread pool.
339 | *
340 | * @param task The task to execute.
341 | * @param priority The priority of thread in the poll.
342 | * @param The type of the task's result.
343 | */
344 | public static void executeBySingle(final Task task,
345 | @IntRange(from = 1, to = 10) final int priority) {
346 | execute(getPoolByTypeAndPriority(TYPE_SINGLE, priority), task);
347 | }
348 |
349 | /**
350 | * Executes the given task in a single thread pool after the given delay.
351 | *
352 | * @param task The task to execute.
353 | * @param delay The time from now to delay execution.
354 | * @param unit The time unit of the delay parameter.
355 | * @param The type of the task's result.
356 | */
357 | public static void executeBySingleWithDelay(final Task task,
358 | final long delay,
359 | final TimeUnit unit) {
360 | executeWithDelay(getPoolByTypeAndPriority(TYPE_SINGLE), task, delay, unit);
361 | }
362 |
363 | /**
364 | * Executes the given task in a single thread pool after the given delay.
365 | *
366 | * @param task The task to execute.
367 | * @param delay The time from now to delay execution.
368 | * @param unit The time unit of the delay parameter.
369 | * @param priority The priority of thread in the poll.
370 | * @param The type of the task's result.
371 | */
372 | public static void executeBySingleWithDelay(final Task task,
373 | final long delay,
374 | final TimeUnit unit,
375 | @IntRange(from = 1, to = 10) final int priority) {
376 | executeWithDelay(getPoolByTypeAndPriority(TYPE_SINGLE, priority), task, delay, unit);
377 | }
378 |
379 | /**
380 | * Executes the given task in a single thread pool at fix rate.
381 | *
382 | * @param task The task to execute.
383 | * @param period The period between successive executions.
384 | * @param unit The time unit of the period parameter.
385 | * @param The type of the task's result.
386 | */
387 | public static void executeBySingleAtFixRate(final Task task,
388 | final long period,
389 | final TimeUnit unit) {
390 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_SINGLE), task, 0, period, unit);
391 | }
392 |
393 | /**
394 | * Executes the given task in a single thread pool at fix rate.
395 | *
396 | * @param task The task to execute.
397 | * @param period The period between successive executions.
398 | * @param unit The time unit of the period parameter.
399 | * @param priority The priority of thread in the poll.
400 | * @param The type of the task's result.
401 | */
402 | public static void executeBySingleAtFixRate(final Task task,
403 | final long period,
404 | final TimeUnit unit,
405 | @IntRange(from = 1, to = 10) final int priority) {
406 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_SINGLE, priority), task, 0, period, unit);
407 | }
408 |
409 | /**
410 | * Executes the given task in a single thread pool at fix rate.
411 | *
412 | * @param task The task to execute.
413 | * @param initialDelay The time to delay first execution.
414 | * @param period The period between successive executions.
415 | * @param unit The time unit of the initialDelay and period parameters.
416 | * @param The type of the task's result.
417 | */
418 | public static void executeBySingleAtFixRate(final Task task,
419 | long initialDelay,
420 | final long period,
421 | final TimeUnit unit) {
422 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_SINGLE), task, initialDelay, period, unit);
423 | }
424 |
425 | /**
426 | * Executes the given task in a single thread pool at fix rate.
427 | *
428 | * @param task The task to execute.
429 | * @param initialDelay The time to delay first execution.
430 | * @param period The period between successive executions.
431 | * @param unit The time unit of the initialDelay and period parameters.
432 | * @param priority The priority of thread in the poll.
433 | * @param The type of the task's result.
434 | */
435 | public static void executeBySingleAtFixRate(final Task task,
436 | long initialDelay,
437 | final long period,
438 | final TimeUnit unit,
439 | @IntRange(from = 1, to = 10) final int priority) {
440 | executeAtFixedRate(
441 | getPoolByTypeAndPriority(TYPE_SINGLE, priority), task, initialDelay, period, unit
442 | );
443 | }
444 |
445 | /**
446 | * Executes the given task in a cached thread pool.
447 | *
448 | * @param task The task to execute.
449 | * @param The type of the task's result.
450 | */
451 | public static void executeByCached(final Task task) {
452 | execute(getPoolByTypeAndPriority(TYPE_CACHED), task);
453 | }
454 |
455 | /**
456 | * Executes the given task in a cached thread pool.
457 | *
458 | * @param task The task to execute.
459 | * @param priority The priority of thread in the poll.
460 | * @param The type of the task's result.
461 | */
462 | public static void executeByCached(final Task task,
463 | @IntRange(from = 1, to = 10) final int priority) {
464 | execute(getPoolByTypeAndPriority(TYPE_CACHED, priority), task);
465 | }
466 |
467 | /**
468 | * Executes the given task in a cached thread pool after the given delay.
469 | *
470 | * @param task The task to execute.
471 | * @param delay The time from now to delay execution.
472 | * @param unit The time unit of the delay parameter.
473 | * @param The type of the task's result.
474 | */
475 | public static void executeByCachedWithDelay(final Task task,
476 | final long delay,
477 | final TimeUnit unit) {
478 | executeWithDelay(getPoolByTypeAndPriority(TYPE_CACHED), task, delay, unit);
479 | }
480 |
481 | /**
482 | * Executes the given task in a cached thread pool after the given delay.
483 | *
484 | * @param task The task to execute.
485 | * @param delay The time from now to delay execution.
486 | * @param unit The time unit of the delay parameter.
487 | * @param priority The priority of thread in the poll.
488 | * @param The type of the task's result.
489 | */
490 | public static void executeByCachedWithDelay(final Task task,
491 | final long delay,
492 | final TimeUnit unit,
493 | @IntRange(from = 1, to = 10) final int priority) {
494 | executeWithDelay(getPoolByTypeAndPriority(TYPE_CACHED, priority), task, delay, unit);
495 | }
496 |
497 | /**
498 | * Executes the given task in a cached thread pool at fix rate.
499 | *
500 | * @param task The task to execute.
501 | * @param period The period between successive executions.
502 | * @param unit The time unit of the period parameter.
503 | * @param The type of the task's result.
504 | */
505 | public static void executeByCachedAtFixRate(final Task task,
506 | final long period,
507 | final TimeUnit unit) {
508 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_CACHED), task, 0, period, unit);
509 | }
510 |
511 | /**
512 | * Executes the given task in a cached thread pool at fix rate.
513 | *
514 | * @param task The task to execute.
515 | * @param period The period between successive executions.
516 | * @param unit The time unit of the period parameter.
517 | * @param priority The priority of thread in the poll.
518 | * @param The type of the task's result.
519 | */
520 | public static void executeByCachedAtFixRate(final Task task,
521 | final long period,
522 | final TimeUnit unit,
523 | @IntRange(from = 1, to = 10) final int priority) {
524 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_CACHED, priority), task, 0, period, unit);
525 | }
526 |
527 | /**
528 | * Executes the given task in a cached thread pool at fix rate.
529 | *
530 | * @param task The task to execute.
531 | * @param initialDelay The time to delay first execution.
532 | * @param period The period between successive executions.
533 | * @param unit The time unit of the initialDelay and period parameters.
534 | * @param The type of the task's result.
535 | */
536 | public static void executeByCachedAtFixRate(final Task task,
537 | long initialDelay,
538 | final long period,
539 | final TimeUnit unit) {
540 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_CACHED), task, initialDelay, period, unit);
541 | }
542 |
543 | /**
544 | * Executes the given task in a cached thread pool at fix rate.
545 | *
546 | * @param task The task to execute.
547 | * @param initialDelay The time to delay first execution.
548 | * @param period The period between successive executions.
549 | * @param unit The time unit of the initialDelay and period parameters.
550 | * @param priority The priority of thread in the poll.
551 | * @param The type of the task's result.
552 | */
553 | public static void executeByCachedAtFixRate(final Task task,
554 | long initialDelay,
555 | final long period,
556 | final TimeUnit unit,
557 | @IntRange(from = 1, to = 10) final int priority) {
558 | executeAtFixedRate(
559 | getPoolByTypeAndPriority(TYPE_CACHED, priority), task, initialDelay, period, unit
560 | );
561 | }
562 |
563 | /**
564 | * Executes the given task in an IO thread pool.
565 | *
566 | * @param task The task to execute.
567 | * @param The type of the task's result.
568 | */
569 | public static void executeByIo(final Task task) {
570 | execute(getPoolByTypeAndPriority(TYPE_IO), task);
571 | }
572 |
573 | /**
574 | * Executes the given task in an IO thread pool.
575 | *
576 | * @param task The task to execute.
577 | * @param priority The priority of thread in the poll.
578 | * @param The type of the task's result.
579 | */
580 | public static void executeByIo(final Task task,
581 | @IntRange(from = 1, to = 10) final int priority) {
582 | execute(getPoolByTypeAndPriority(TYPE_IO, priority), task);
583 | }
584 |
585 | /**
586 | * Executes the given task in an IO thread pool after the given delay.
587 | *
588 | * @param task The task to execute.
589 | * @param delay The time from now to delay execution.
590 | * @param unit The time unit of the delay parameter.
591 | * @param The type of the task's result.
592 | */
593 | public static void executeByIoWithDelay(final Task task,
594 | final long delay,
595 | final TimeUnit unit) {
596 | executeWithDelay(getPoolByTypeAndPriority(TYPE_IO), task, delay, unit);
597 | }
598 |
599 | /**
600 | * Executes the given task in an IO thread pool after the given delay.
601 | *
602 | * @param task The task to execute.
603 | * @param delay The time from now to delay execution.
604 | * @param unit The time unit of the delay parameter.
605 | * @param priority The priority of thread in the poll.
606 | * @param The type of the task's result.
607 | */
608 | public static void executeByIoWithDelay(final Task task,
609 | final long delay,
610 | final TimeUnit unit,
611 | @IntRange(from = 1, to = 10) final int priority) {
612 | executeWithDelay(getPoolByTypeAndPriority(TYPE_IO, priority), task, delay, unit);
613 | }
614 |
615 | /**
616 | * Executes the given task in an IO thread pool at fix rate.
617 | *
618 | * @param task The task to execute.
619 | * @param period The period between successive executions.
620 | * @param unit The time unit of the period parameter.
621 | * @param The type of the task's result.
622 | */
623 | public static void executeByIoAtFixRate(final Task task,
624 | final long period,
625 | final TimeUnit unit) {
626 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_IO), task, 0, period, unit);
627 | }
628 |
629 | /**
630 | * Executes the given task in an IO thread pool at fix rate.
631 | *
632 | * @param task The task to execute.
633 | * @param period The period between successive executions.
634 | * @param unit The time unit of the period parameter.
635 | * @param priority The priority of thread in the poll.
636 | * @param The type of the task's result.
637 | */
638 | public static void executeByIoAtFixRate(final Task task,
639 | final long period,
640 | final TimeUnit unit,
641 | @IntRange(from = 1, to = 10) final int priority) {
642 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_IO, priority), task, 0, period, unit);
643 | }
644 |
645 | /**
646 | * Executes the given task in an IO thread pool at fix rate.
647 | *
648 | * @param task The task to execute.
649 | * @param initialDelay The time to delay first execution.
650 | * @param period The period between successive executions.
651 | * @param unit The time unit of the initialDelay and period parameters.
652 | * @param The type of the task's result.
653 | */
654 | public static void executeByIoAtFixRate(final Task task,
655 | long initialDelay,
656 | final long period,
657 | final TimeUnit unit) {
658 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_IO), task, initialDelay, period, unit);
659 | }
660 |
661 | /**
662 | * Executes the given task in an IO thread pool at fix rate.
663 | *
664 | * @param task The task to execute.
665 | * @param initialDelay The time to delay first execution.
666 | * @param period The period between successive executions.
667 | * @param unit The time unit of the initialDelay and period parameters.
668 | * @param priority The priority of thread in the poll.
669 | * @param The type of the task's result.
670 | */
671 | public static void executeByIoAtFixRate(final Task task,
672 | long initialDelay,
673 | final long period,
674 | final TimeUnit unit,
675 | @IntRange(from = 1, to = 10) final int priority) {
676 | executeAtFixedRate(
677 | getPoolByTypeAndPriority(TYPE_IO, priority), task, initialDelay, period, unit
678 | );
679 | }
680 |
681 | /**
682 | * Executes the given task in a cpu thread pool.
683 | *
684 | * @param task The task to execute.
685 | * @param The type of the task's result.
686 | */
687 | public static void executeByCpu(final Task task) {
688 | execute(getPoolByTypeAndPriority(TYPE_CPU), task);
689 | }
690 |
691 | /**
692 | * Executes the given task in a cpu thread pool.
693 | *
694 | * @param task The task to execute.
695 | * @param priority The priority of thread in the poll.
696 | * @param The type of the task's result.
697 | */
698 | public static void executeByCpu(final Task task,
699 | @IntRange(from = 1, to = 10) final int priority) {
700 | execute(getPoolByTypeAndPriority(TYPE_CPU, priority), task);
701 | }
702 |
703 | /**
704 | * Executes the given task in a cpu thread pool after the given delay.
705 | *
706 | * @param task The task to execute.
707 | * @param delay The time from now to delay execution.
708 | * @param unit The time unit of the delay parameter.
709 | * @param The type of the task's result.
710 | */
711 | public static void executeByCpuWithDelay(final Task task,
712 | final long delay,
713 | final TimeUnit unit) {
714 | executeWithDelay(getPoolByTypeAndPriority(TYPE_CPU), task, delay, unit);
715 | }
716 |
717 | /**
718 | * Executes the given task in a cpu thread pool after the given delay.
719 | *
720 | * @param task The task to execute.
721 | * @param delay The time from now to delay execution.
722 | * @param unit The time unit of the delay parameter.
723 | * @param priority The priority of thread in the poll.
724 | * @param The type of the task's result.
725 | */
726 | public static void executeByCpuWithDelay(final Task task,
727 | final long delay,
728 | final TimeUnit unit,
729 | @IntRange(from = 1, to = 10) final int priority) {
730 | executeWithDelay(getPoolByTypeAndPriority(TYPE_CPU, priority), task, delay, unit);
731 | }
732 |
733 | /**
734 | * Executes the given task in a cpu thread pool at fix rate.
735 | *
736 | * @param task The task to execute.
737 | * @param period The period between successive executions.
738 | * @param unit The time unit of the period parameter.
739 | * @param The type of the task's result.
740 | */
741 | public static void executeByCpuAtFixRate(final Task task,
742 | final long period,
743 | final TimeUnit unit) {
744 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_CPU), task, 0, period, unit);
745 | }
746 |
747 | /**
748 | * Executes the given task in a cpu thread pool at fix rate.
749 | *
750 | * @param task The task to execute.
751 | * @param period The period between successive executions.
752 | * @param unit The time unit of the period parameter.
753 | * @param priority The priority of thread in the poll.
754 | * @param The type of the task's result.
755 | */
756 | public static void executeByCpuAtFixRate(final Task task,
757 | final long period,
758 | final TimeUnit unit,
759 | @IntRange(from = 1, to = 10) final int priority) {
760 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_CPU, priority), task, 0, period, unit);
761 | }
762 |
763 | /**
764 | * Executes the given task in a cpu thread pool at fix rate.
765 | *
766 | * @param task The task to execute.
767 | * @param initialDelay The time to delay first execution.
768 | * @param period The period between successive executions.
769 | * @param unit The time unit of the initialDelay and period parameters.
770 | * @param The type of the task's result.
771 | */
772 | public static void executeByCpuAtFixRate(final Task task,
773 | long initialDelay,
774 | final long period,
775 | final TimeUnit unit) {
776 | executeAtFixedRate(getPoolByTypeAndPriority(TYPE_CPU), task, initialDelay, period, unit);
777 | }
778 |
779 | /**
780 | * Executes the given task in a cpu thread pool at fix rate.
781 | *
782 | * @param task The task to execute.
783 | * @param initialDelay The time to delay first execution.
784 | * @param period The period between successive executions.
785 | * @param unit The time unit of the initialDelay and period parameters.
786 | * @param priority The priority of thread in the poll.
787 | * @param The type of the task's result.
788 | */
789 | public static void executeByCpuAtFixRate(final Task task,
790 | long initialDelay,
791 | final long period,
792 | final TimeUnit unit,
793 | @IntRange(from = 1, to = 10) final int priority) {
794 | executeAtFixedRate(
795 | getPoolByTypeAndPriority(TYPE_CPU, priority), task, initialDelay, period, unit
796 | );
797 | }
798 |
799 | /**
800 | * Executes the given task in a custom thread pool.
801 | *
802 | * @param pool The custom thread pool.
803 | * @param task The task to execute.
804 | * @param The type of the task's result.
805 | */
806 | public static void executeByCustom(final ExecutorService pool, final Task task) {
807 | execute(pool, task);
808 | }
809 |
810 | /**
811 | * Executes the given task in a custom thread pool after the given delay.
812 | *
813 | * @param pool The custom thread pool.
814 | * @param task The task to execute.
815 | * @param delay The time from now to delay execution.
816 | * @param unit The time unit of the delay parameter.
817 | * @param The type of the task's result.
818 | */
819 | public static void executeByCustomWithDelay(final ExecutorService pool,
820 | final Task task,
821 | final long delay,
822 | final TimeUnit unit) {
823 | executeWithDelay(pool, task, delay, unit);
824 | }
825 |
826 | /**
827 | * Executes the given task in a custom thread pool at fix rate.
828 | *
829 | * @param pool The custom thread pool.
830 | * @param task The task to execute.
831 | * @param period The period between successive executions.
832 | * @param unit The time unit of the period parameter.
833 | * @param The type of the task's result.
834 | */
835 | public static void executeByCustomAtFixRate(final ExecutorService pool,
836 | final Task task,
837 | final long period,
838 | final TimeUnit unit) {
839 | executeAtFixedRate(pool, task, 0, period, unit);
840 | }
841 |
842 | /**
843 | * Executes the given task in a custom thread pool at fix rate.
844 | *
845 | * @param pool The custom thread pool.
846 | * @param task The task to execute.
847 | * @param initialDelay The time to delay first execution.
848 | * @param period The period between successive executions.
849 | * @param unit The time unit of the initialDelay and period parameters.
850 | * @param The type of the task's result.
851 | */
852 | public static void executeByCustomAtFixRate(final ExecutorService pool,
853 | final Task task,
854 | long initialDelay,
855 | final long period,
856 | final TimeUnit unit) {
857 | executeAtFixedRate(pool, task, initialDelay, period, unit);
858 | }
859 |
860 | /**
861 | * Cancel the given task.
862 | *
863 | * @param task The task to cancel.
864 | */
865 | public static void cancel(final Task task) {
866 | if (task == null) return;
867 | task.cancel();
868 | }
869 |
870 | /**
871 | * Cancel the given tasks.
872 | *
873 | * @param tasks The tasks to cancel.
874 | */
875 | public static void cancel(final Task... tasks) {
876 | if (tasks == null || tasks.length == 0) return;
877 | for (Task task : tasks) {
878 | if (task == null) continue;
879 | task.cancel();
880 | }
881 | }
882 |
883 | /**
884 | * Cancel the given tasks.
885 | *
886 | * @param tasks The tasks to cancel.
887 | */
888 | public static void cancel(final List tasks) {
889 | if (tasks == null || tasks.size() == 0) return;
890 | for (Task task : tasks) {
891 | if (task == null) continue;
892 | task.cancel();
893 | }
894 | }
895 |
896 | /**
897 | * Cancel the tasks in pool.
898 | *
899 | * @param executorService The pool.
900 | */
901 | public static void cancel(ExecutorService executorService) {
902 | if (executorService instanceof ThreadPoolExecutor4Util) {
903 | for (Map.Entry taskTaskInfoEntry : TASK_POOL_MAP.entrySet()) {
904 | if (taskTaskInfoEntry.getValue() == executorService) {
905 | cancel(taskTaskInfoEntry.getKey());
906 | }
907 | }
908 | } else {
909 | Log.e("ThreadUtils", "The executorService is not ThreadUtils's pool.");
910 | }
911 | }
912 |
913 | /**
914 | * Set the deliver.
915 | *
916 | * @param deliver The deliver.
917 | */
918 | public static void setDeliver(final Executor deliver) {
919 | sDeliver = deliver;
920 | }
921 |
922 | private static void execute(final ExecutorService pool, final Task task) {
923 | execute(pool, task, 0, 0, null);
924 | }
925 |
926 | private static void executeWithDelay(final ExecutorService pool,
927 | final Task task,
928 | final long delay,
929 | final TimeUnit unit) {
930 | execute(pool, task, delay, 0, unit);
931 | }
932 |
933 | private static void executeAtFixedRate(final ExecutorService pool,
934 | final Task task,
935 | long delay,
936 | final long period,
937 | final TimeUnit unit) {
938 | execute(pool, task, delay, period, unit);
939 | }
940 |
941 | private static void execute(final ExecutorService pool, final Task task,
942 | long delay, final long period, final TimeUnit unit) {
943 | synchronized (TASK_POOL_MAP) {
944 | if (TASK_POOL_MAP.get(task) != null) {
945 | Log.e("ThreadUtils", "Task can only be executed once.");
946 | return;
947 | }
948 | TASK_POOL_MAP.put(task, pool);
949 | }
950 | if (period == 0) {
951 | if (delay == 0) {
952 | pool.execute(task);
953 | } else {
954 | TimerTask timerTask = new TimerTask() {
955 | @Override
956 | public void run() {
957 | pool.execute(task);
958 | }
959 | };
960 | TIMER.schedule(timerTask, unit.toMillis(delay));
961 | }
962 | } else {
963 | task.setSchedule(true);
964 | TimerTask timerTask = new TimerTask() {
965 | @Override
966 | public void run() {
967 | pool.execute(task);
968 | }
969 | };
970 | TIMER.scheduleAtFixedRate(timerTask, unit.toMillis(delay), unit.toMillis(period));
971 | }
972 | }
973 |
974 | private static ExecutorService getPoolByTypeAndPriority(final int type) {
975 | return getPoolByTypeAndPriority(type, Thread.NORM_PRIORITY);
976 | }
977 |
978 | private static ExecutorService getPoolByTypeAndPriority(final int type, final int priority) {
979 | synchronized (TYPE_PRIORITY_POOLS) {
980 | ExecutorService pool;
981 | Map priorityPools = TYPE_PRIORITY_POOLS.get(type);
982 | if (priorityPools == null) {
983 | priorityPools = new ConcurrentHashMap<>();
984 | pool = ThreadPoolExecutor4Util.createPool(type, priority);
985 | priorityPools.put(priority, pool);
986 | TYPE_PRIORITY_POOLS.put(type, priorityPools);
987 | } else {
988 | pool = priorityPools.get(priority);
989 | if (pool == null) {
990 | pool = ThreadPoolExecutor4Util.createPool(type, priority);
991 | priorityPools.put(priority, pool);
992 | }
993 | }
994 | return pool;
995 | }
996 | }
997 |
998 | static final class ThreadPoolExecutor4Util extends ThreadPoolExecutor {
999 |
1000 | private static ExecutorService createPool(final int type, final int priority) {
1001 | switch (type) {
1002 | case TYPE_SINGLE:
1003 | return new ThreadPoolExecutor4Util(1, 1,
1004 | 0L, TimeUnit.MILLISECONDS,
1005 | new LinkedBlockingQueue4Util(),
1006 | new UtilsThreadFactory("single", priority)
1007 | );
1008 | case TYPE_CACHED:
1009 | return new ThreadPoolExecutor4Util(0, 128,
1010 | 60L, TimeUnit.SECONDS,
1011 | new LinkedBlockingQueue4Util(true),
1012 | new UtilsThreadFactory("cached", priority)
1013 | );
1014 | case TYPE_IO:
1015 | return new ThreadPoolExecutor4Util(2 * CPU_COUNT + 1, 2 * CPU_COUNT + 1,
1016 | 30, TimeUnit.SECONDS,
1017 | new LinkedBlockingQueue4Util(),
1018 | new UtilsThreadFactory("io", priority)
1019 | );
1020 | case TYPE_CPU:
1021 | return new ThreadPoolExecutor4Util(CPU_COUNT + 1, 2 * CPU_COUNT + 1,
1022 | 30, TimeUnit.SECONDS,
1023 | new LinkedBlockingQueue4Util(true),
1024 | new UtilsThreadFactory("cpu", priority)
1025 | );
1026 | default:
1027 | return new ThreadPoolExecutor4Util(type, type,
1028 | 0L, TimeUnit.MILLISECONDS,
1029 | new LinkedBlockingQueue4Util(),
1030 | new UtilsThreadFactory("fixed(" + type + ")", priority)
1031 | );
1032 | }
1033 | }
1034 |
1035 | private final AtomicInteger mSubmittedCount = new AtomicInteger();
1036 |
1037 | private final LinkedBlockingQueue4Util mWorkQueue;
1038 |
1039 | ThreadPoolExecutor4Util(int corePoolSize, int maximumPoolSize,
1040 | long keepAliveTime, TimeUnit unit,
1041 | LinkedBlockingQueue4Util workQueue,
1042 | ThreadFactory threadFactory) {
1043 | super(corePoolSize, maximumPoolSize,
1044 | keepAliveTime, unit,
1045 | workQueue,
1046 | threadFactory
1047 | );
1048 | workQueue.mPool = this;
1049 | mWorkQueue = workQueue;
1050 | }
1051 |
1052 | private int getSubmittedCount() {
1053 | return mSubmittedCount.get();
1054 | }
1055 |
1056 | @Override
1057 | protected void afterExecute(Runnable r, Throwable t) {
1058 | mSubmittedCount.decrementAndGet();
1059 | super.afterExecute(r, t);
1060 | }
1061 |
1062 | @Override
1063 | public void execute(@NonNull Runnable command) {
1064 | if (this.isShutdown()) {
1065 | return;
1066 | }
1067 | mSubmittedCount.incrementAndGet();
1068 | try {
1069 | super.execute(command);
1070 | } catch (RejectedExecutionException ignore) {
1071 | Log.e("ThreadUtils", "This will not happen!");
1072 | mWorkQueue.offer(command);
1073 | } catch (Throwable t) {
1074 | mSubmittedCount.decrementAndGet();
1075 | }
1076 | }
1077 | }
1078 |
1079 | private static final class LinkedBlockingQueue4Util extends LinkedBlockingQueue {
1080 |
1081 | private volatile ThreadPoolExecutor4Util mPool;
1082 |
1083 | private int mCapacity = Integer.MAX_VALUE;
1084 |
1085 | LinkedBlockingQueue4Util() {
1086 | super();
1087 | }
1088 |
1089 | LinkedBlockingQueue4Util(boolean isAddSubThreadFirstThenAddQueue) {
1090 | super();
1091 | if (isAddSubThreadFirstThenAddQueue) {
1092 | mCapacity = 0;
1093 | }
1094 | }
1095 |
1096 | LinkedBlockingQueue4Util(int capacity) {
1097 | super();
1098 | mCapacity = capacity;
1099 | }
1100 |
1101 | @Override
1102 | public boolean offer(@NonNull Runnable runnable) {
1103 | if (mCapacity <= size() &&
1104 | mPool != null && mPool.getPoolSize() < mPool.getMaximumPoolSize()) {
1105 | // create a non-core thread
1106 | return false;
1107 | }
1108 | return super.offer(runnable);
1109 | }
1110 | }
1111 |
1112 | static final class UtilsThreadFactory extends AtomicLong
1113 | implements ThreadFactory {
1114 | private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);
1115 | private static final long serialVersionUID = -9209200509960368598L;
1116 | private final String namePrefix;
1117 | private final int priority;
1118 | private final boolean isDaemon;
1119 |
1120 | UtilsThreadFactory(String prefix, int priority) {
1121 | this(prefix, priority, false);
1122 | }
1123 |
1124 | UtilsThreadFactory(String prefix, int priority, boolean isDaemon) {
1125 | namePrefix = prefix + "-pool-" +
1126 | POOL_NUMBER.getAndIncrement() +
1127 | "-thread-";
1128 | this.priority = priority;
1129 | this.isDaemon = isDaemon;
1130 | }
1131 |
1132 | @Override
1133 | public Thread newThread(@NonNull Runnable r) {
1134 | Thread t = new Thread(r, namePrefix + getAndIncrement()) {
1135 | @Override
1136 | public void run() {
1137 | try {
1138 | super.run();
1139 | } catch (Throwable t) {
1140 | Log.e("ThreadUtils", "Request threw uncaught throwable", t);
1141 | }
1142 | }
1143 | };
1144 | t.setDaemon(isDaemon);
1145 | t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
1146 | @Override
1147 | public void uncaughtException(Thread t, Throwable e) {
1148 | System.out.println(e);
1149 | }
1150 | });
1151 | t.setPriority(priority);
1152 | return t;
1153 | }
1154 | }
1155 |
1156 | public abstract static class SimpleTask extends Task {
1157 |
1158 | @Override
1159 | public void onCancel() {
1160 | Log.e("ThreadUtils", "onCancel: " + Thread.currentThread());
1161 | }
1162 |
1163 | @Override
1164 | public void onFail(Throwable t) {
1165 | Log.e("ThreadUtils", "onFail: ", t);
1166 | }
1167 |
1168 | }
1169 |
1170 | public abstract static class Task implements Runnable {
1171 |
1172 | private static final int NEW = 0;
1173 | private static final int RUNNING = 1;
1174 | private static final int EXCEPTIONAL = 2;
1175 | private static final int COMPLETING = 3;
1176 | private static final int CANCELLED = 4;
1177 | private static final int INTERRUPTED = 5;
1178 | private static final int TIMEOUT = 6;
1179 |
1180 | private final AtomicInteger state = new AtomicInteger(NEW);
1181 |
1182 | private volatile boolean isSchedule;
1183 | private volatile Thread runner;
1184 |
1185 | private Timer mTimer;
1186 | private long mTimeoutMillis;
1187 | private OnTimeoutListener mTimeoutListener;
1188 |
1189 | private Executor deliver;
1190 |
1191 | public abstract T doInBackground() throws Throwable;
1192 |
1193 | public abstract void onSuccess(T result);
1194 |
1195 | public abstract void onCancel();
1196 |
1197 | public abstract void onFail(Throwable t);
1198 |
1199 | @Override
1200 | public void run() {
1201 | if (isSchedule) {
1202 | if (runner == null) {
1203 | if (!state.compareAndSet(NEW, RUNNING)) {
1204 | return;
1205 | }
1206 | runner = Thread.currentThread();
1207 | if (mTimeoutListener != null) {
1208 | Log.w("ThreadUtils", "Scheduled task doesn't support timeout.");
1209 | }
1210 | } else {
1211 | if (state.get() != RUNNING) {
1212 | return;
1213 | }
1214 | }
1215 | } else {
1216 | if (!state.compareAndSet(NEW, RUNNING)) {
1217 | return;
1218 | }
1219 | runner = Thread.currentThread();
1220 | if (mTimeoutListener != null) {
1221 | mTimer = new Timer();
1222 | mTimer.schedule(new TimerTask() {
1223 | @Override
1224 | public void run() {
1225 | if (!isDone() && mTimeoutListener != null) {
1226 | timeout();
1227 | mTimeoutListener.onTimeout();
1228 | onDone();
1229 | }
1230 | }
1231 | }, mTimeoutMillis);
1232 | }
1233 | }
1234 | try {
1235 | final T result = doInBackground();
1236 | if (isSchedule) {
1237 | if (state.get() != RUNNING) {
1238 | return;
1239 | }
1240 | getDeliver().execute(new Runnable() {
1241 | @Override
1242 | public void run() {
1243 | onSuccess(result);
1244 | }
1245 | });
1246 | } else {
1247 | if (!state.compareAndSet(RUNNING, COMPLETING)) {
1248 | return;
1249 | }
1250 | getDeliver().execute(new Runnable() {
1251 | @Override
1252 | public void run() {
1253 | onSuccess(result);
1254 | onDone();
1255 | }
1256 | });
1257 | }
1258 | } catch (InterruptedException ignore) {
1259 | state.compareAndSet(CANCELLED, INTERRUPTED);
1260 | } catch (final Throwable throwable) {
1261 | if (!state.compareAndSet(RUNNING, EXCEPTIONAL)) {
1262 | return;
1263 | }
1264 | getDeliver().execute(new Runnable() {
1265 | @Override
1266 | public void run() {
1267 | onFail(throwable);
1268 | onDone();
1269 | }
1270 | });
1271 | }
1272 | }
1273 |
1274 | public void cancel() {
1275 | cancel(true);
1276 | }
1277 |
1278 | public void cancel(boolean mayInterruptIfRunning) {
1279 | synchronized (state) {
1280 | if (state.get() > RUNNING) {
1281 | return;
1282 | }
1283 | state.set(CANCELLED);
1284 | }
1285 | if (mayInterruptIfRunning) {
1286 | if (runner != null) {
1287 | runner.interrupt();
1288 | }
1289 | }
1290 |
1291 | getDeliver().execute(new Runnable() {
1292 | @Override
1293 | public void run() {
1294 | onCancel();
1295 | onDone();
1296 | }
1297 | });
1298 | }
1299 |
1300 | private void timeout() {
1301 | synchronized (state) {
1302 | if (state.get() > RUNNING) {
1303 | return;
1304 | }
1305 | state.set(TIMEOUT);
1306 | }
1307 | if (runner != null) {
1308 | runner.interrupt();
1309 | }
1310 | }
1311 |
1312 |
1313 | public boolean isCanceled() {
1314 | return state.get() >= CANCELLED;
1315 | }
1316 |
1317 | public boolean isDone() {
1318 | return state.get() > RUNNING;
1319 | }
1320 |
1321 | public Task setDeliver(Executor deliver) {
1322 | this.deliver = deliver;
1323 | return this;
1324 | }
1325 |
1326 | /**
1327 | * Scheduled task doesn't support timeout.
1328 | */
1329 | public Task setTimeout(final long timeoutMillis, final OnTimeoutListener listener) {
1330 | mTimeoutMillis = timeoutMillis;
1331 | mTimeoutListener = listener;
1332 | return this;
1333 | }
1334 |
1335 | private void setSchedule(boolean isSchedule) {
1336 | this.isSchedule = isSchedule;
1337 | }
1338 |
1339 | private Executor getDeliver() {
1340 | if (deliver == null) {
1341 | return getGlobalDeliver();
1342 | }
1343 | return deliver;
1344 | }
1345 |
1346 | @CallSuper
1347 | protected void onDone() {
1348 | TASK_POOL_MAP.remove(this);
1349 | if (mTimer != null) {
1350 | mTimer.cancel();
1351 | mTimer = null;
1352 | mTimeoutListener = null;
1353 | }
1354 | }
1355 |
1356 | public interface OnTimeoutListener {
1357 | void onTimeout();
1358 | }
1359 | }
1360 |
1361 | public static class SyncValue {
1362 |
1363 | private final CountDownLatch mLatch = new CountDownLatch(1);
1364 | private final AtomicBoolean mFlag = new AtomicBoolean();
1365 | private T mValue;
1366 |
1367 | public void setValue(T value) {
1368 | if (mFlag.compareAndSet(false, true)) {
1369 | mValue = value;
1370 | mLatch.countDown();
1371 | }
1372 | }
1373 |
1374 | public T getValue() {
1375 | if (!mFlag.get()) {
1376 | try {
1377 | mLatch.await();
1378 | } catch (InterruptedException e) {
1379 | e.printStackTrace();
1380 | }
1381 | }
1382 | return mValue;
1383 | }
1384 |
1385 | public T getValue(long timeout, TimeUnit unit, T defaultValue) {
1386 | if (!mFlag.get()) {
1387 | try {
1388 | mLatch.await(timeout, unit);
1389 | } catch (InterruptedException e) {
1390 | e.printStackTrace();
1391 | return defaultValue;
1392 | }
1393 | }
1394 | return mValue;
1395 | }
1396 | }
1397 |
1398 | private static Executor getGlobalDeliver() {
1399 | if (sDeliver == null) {
1400 | sDeliver = new Executor() {
1401 | @Override
1402 | public void execute(@NonNull Runnable command) {
1403 | runOnUiThread(command);
1404 | }
1405 | };
1406 | }
1407 | return sDeliver;
1408 | }
1409 | }
1410 |
--------------------------------------------------------------------------------