更新:与问题所有者讨论后,这是最终提出的解决方案,附代码:
package toys;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
public class TwoQueues {
//tweak it for your purpose.
private final int CPU_COUNT = 4;
private BlockingQueue<Runnable> lightTaskQueue = new LinkedBlockingDeque<Runnable>();
private ThreadPoolExecutor lightExecutor = new ThreadPoolExecutor(CPU_COUNT, CPU_COUNT, 60L, TimeUnit.SECONDS, lightTaskQueue);
private BlockingQueue<Runnable> heavyTaskQueue = new LinkedBlockingDeque<Runnable>();
private ThreadPoolExecutor heavyExecutor = new ThreadPoolExecutor(1, 1, 60L, TimeUnit.SECONDS, heavyTaskQueue);
public static class SampleLightTask implements Runnable {
@Override
public void run() {
System.out.println("I am " + this + " and running fast!");
}
}
private static AtomicBoolean heavyTaskRunning = new AtomicBoolean();
public static class SampleHeavyTask implements Runnable {
@Override
public void run() {
try {
heavyTaskRunning.set(true);
System.out.println("I am " + this + " and running quite slow!");
final long start = System.currentTimeMillis();
while (true) {
//burn the CPU for ten senconds.
if (System.currentTimeMillis()-start >= 10000L)
break;
}
} finally {
heavyTaskRunning.set(false);;
}
}
}
public void shutDownNow() {
this.lightExecutor.shutdownNow();
this.heavyExecutor.shutdownNow();
}
public void runOrQueueLightTask(SampleLightTask lightOne) {
this.lightExecutor.execute(lightOne);
}
public void runOrQueueHeavyTask(SampleHeavyTask heavyOne) {
if (heavyTaskRunning.get()) {
System.out.println("running, skipped new one: " + heavyOne);
return;
}
this.heavyExecutor.execute(heavyOne);
}
public static void main(String[] args) throws Exception {
TwoQueues q = new TwoQueues();
final long start = System.currentTimeMillis();
//Run the queues for 30 seconds, add CPU-light and CPU-weight tasks
//every second.
while (System.currentTimeMillis()-start<=30*1000L) {
q.runOrQueueHeavyTask(new SampleHeavyTask());
q.runOrQueueLightTask(new SampleLightTask());
Thread.sleep(1000L);
}
q.shutDownNow();
}
}
以及运行输出:
I am toys.TwoQueues$SampleHeavyTask@6d0cecb2 and running quite slow!
I am toys.TwoQueues$SampleLightTask@6b87d20c and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@2ce07e6b
I am toys.TwoQueues$SampleLightTask@7fa0d111 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@16fdf48d
I am toys.TwoQueues$SampleLightTask@5fbd7d0e and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@115d533d
I am toys.TwoQueues$SampleLightTask@59c27402 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@6d4e5d57
I am toys.TwoQueues$SampleLightTask@33d232d1 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@79ec3264
I am toys.TwoQueues$SampleLightTask@1e081c5 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@3a67ad79
I am toys.TwoQueues$SampleLightTask@6cae00e3 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@13bc6ed3
I am toys.TwoQueues$SampleLightTask@380fe8c4 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@1c7ab89d
I am toys.TwoQueues$SampleLightTask@3cee5a06 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@44585f2a
I am toys.TwoQueues$SampleLightTask@5cfe174 and running fast!
I am toys.TwoQueues$SampleLightTask@12da89a7 and running fast!
I am toys.TwoQueues$SampleHeavyTask@49833c9c and running quite slow!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@47004b78
I am toys.TwoQueues$SampleLightTask@645ad7b2 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@8071a97
I am toys.TwoQueues$SampleLightTask@a62b39f and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@55fe910c
I am toys.TwoQueues$SampleLightTask@3be4d6ef and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@2cdb03a1
I am toys.TwoQueues$SampleLightTask@5ecb5608 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@777d57d6
I am toys.TwoQueues$SampleLightTask@4611dfe3 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@3f81d405
I am toys.TwoQueues$SampleLightTask@6486b4d5 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@47ca3f82
I am toys.TwoQueues$SampleLightTask@2f0f94a0 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@27e6ac83
I am toys.TwoQueues$SampleLightTask@1947e0ec and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@3dffb2eb
I am toys.TwoQueues$SampleLightTask@5e3b8219 and running fast!
I am toys.TwoQueues$SampleLightTask@14da67a4 and running fast!
I am toys.TwoQueues$SampleHeavyTask@eca4aae and running quite slow!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@2eced18
I am toys.TwoQueues$SampleLightTask@10c1c428 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@213526b0
I am toys.TwoQueues$SampleLightTask@287efdd8 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@294b84ad
I am toys.TwoQueues$SampleLightTask@1cf38f09 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@3a33a6b8
I am toys.TwoQueues$SampleLightTask@150697e2 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@63dd8136
I am toys.TwoQueues$SampleLightTask@634e3372 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@2313b44d
I am toys.TwoQueues$SampleLightTask@62a23d38 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@9615a1f
I am toys.TwoQueues$SampleLightTask@5663ae08 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@2a36bb87
I am toys.TwoQueues$SampleLightTask@6f51b1b7 and running fast!
running, skipped new one: toys.TwoQueues$SampleHeavyTask@5c6a9e79
I am toys.TwoQueues$SampleLightTask@5bca4955 and running fast!
///////////////////////////////////////////////////////////// //////////////////////
如果我正确理解您的要求,有两种类型的任务:A 类,CPU 密集型,以串行方式执行,并可能修改一些非线程安全的全局状态; B 类,不是 CPU 密集型的,需要尽快完成。
为什么不为此使用两个thread pools 和两个队列呢?这是一个完美的匹配。对于 A 类任务,将它们调度在最大并发设置为 1 的线程池中;对于类型 B,在另一个线程池中,最大并发设置为您的 CPU 核心/线程数或任何适合您需要的东西。这里甚至不需要“检查并优雅地失败”。
我以前自己写了很多这些原始的、低级的并发线程的东西,但是当线程池成为 JDK 中的标准库时,我再也不会回去了,无论是在服务器端(EE)还是客户端(这里是安卓)。设计简洁,性能好,代码少得多,当然,错误少得多。调试与并发相关的错误绝非易事。