顺序执行的Runnable队列
当一个任务需要放到子线程执行时,一般new Runnable就可以了。
可有的时候需要保证Runnable按顺序执行,比如连续收到了推送,这时候可以用子线程队列
以下是EventBus 3.2.0里面的实现方式,抽取出来做技术调研
1.BackgroundPoster
/*
* Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.commonsdk.async;
import android.util.Log;
/**
* Posts events in background.
*
* @author Markus
*/
final public class BackgroundPoster implements Runnable {
private static BackgroundPoster mInstance = null;
public static BackgroundPoster getInstance() {
if (mInstance == null) {
mInstance = new BackgroundPoster();
}
return mInstance;
}
private final PendingPostQueue queue;
private volatile boolean executorRunning;
private BackgroundPoster() {
queue = new PendingPostQueue();
}
public void enqueue(Poster subscription, Object event) {
PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
synchronized (this) {
queue.enqueue(pendingPost);
if (!executorRunning) {
executorRunning = true;
CXThreadPoolManager.getThreadPool().submit(this);
}
}
}
@Override
public void run() {
try {
try {
while (true) {
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
pendingPost.subscription.invoke(pendingPost.event);
}
} catch (InterruptedException e) {
Log.e("BackgroundPoster", Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
}
2.PendingPost
/*
* Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.commonsdk.async;
import java.util.ArrayList;
import java.util.List;
final class PendingPost {
private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();
Object event;
Poster subscription;
PendingPost next;
private PendingPost(Object event, Poster subscription) {
this.event = event;
this.subscription = subscription;
}
static PendingPost obtainPendingPost(Poster subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
if (size > 0) {
PendingPost pendingPost = pendingPostPool.remove(size - 1);
pendingPost.event = event;
pendingPost.subscription = subscription;
pendingPost.next = null;
return pendingPost;
}
}
return new PendingPost(event, subscription);
}
static void releasePendingPost(PendingPost pendingPost) {
pendingPost.event = null;
pendingPost.subscription = null;
pendingPost.next = null;
synchronized (pendingPostPool) {
// Don't let the pool grow indefinitely
if (pendingPostPool.size() < 10000) {
pendingPostPool.add(pendingPost);
}
}
}
}
3.PendingPostQueue
package com.commonsdk.async;
final class PendingPostQueue {
private PendingPost head;
private PendingPost tail;
synchronized void enqueue(PendingPost pendingPost) {
if (pendingPost == null) {
throw new NullPointerException("null cannot be enqueued");
}
if (tail != null) {
tail.next = pendingPost;
tail = pendingPost;
} else if (head == null) {
head = tail = pendingPost;
} else {
throw new IllegalStateException("Head present, but no tail");
}
notifyAll();
}
synchronized PendingPost poll() {
PendingPost pendingPost = head;
if (head != null) {
head = head.next;
if (head == null) {
tail = null;
}
}
return pendingPost;
}
synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
if (head == null) {
wait(maxMillisToWait);
}
return poll();
}
}
4.Poster
/*
* Copyright (C) 2012-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.commonsdk.async;
public interface Poster {
void invoke(Object event);
}
5.使用方法
package cn.platform.util;
import android.content.Intent;
import com.commonsdk.async.BackgroundPoster;
import com.commonsdk.async.Poster;
public class PlatformClient implements Poster {
private static PlatformClient mPlatformClient = null;
public static PlatformClient getInstance() {
if (mPlatformClient == null) {
mPlatformClient = new PlatformClient();
}
return mPlatformClient;
}
public void notifyAction(Intent intent) {
//调用此接口添加进队列
BackgroundPoster.getInstance().enqueue(this, intent);
}
@Override
public void invoke(Object object) {
Intent intent;
if (object != null && object instanceof Intent) {
intent = (Intent) object;
} else {
return;
}
if (intent == null || intent.getAction() == null) {
return;
}
switch (intent.getAction()) {
case "platform_push_command_msg_arrived":
break;
default:
break;
}
}
}