我正在编写一种“按类型搜索”机制(android),该机制在后台线程中进行sqlite查询,并将结果发布回UI线程。理想情况下,线程应等待/休眠,唤醒以执行任何接收到的Runnable对象,然后返回休眠状态。最好的方法是什么?为什么?
基本上,我想了解这3个选项之间的主要区别是什么,哪种是最适合这种情况的
睡眠/中断
public class AsyncExecutorSleepInterrupt {
private static Thread thread;
private static Runnable runnable;
static {
thread = new Thread(() -> {
while (true) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
if (runnable != null) {
runnable.run();
runnable = null;
}
}
}
});
thread.start();
}
public static void execute(Runnable runnable) {
AsyncExecutorSleepInterrupt.runnable = runnable;
thread.interrupt();
}}
等待/通知
public class AsyncExecutorWaitNotify {
private static Thread thread;
private static Runnable runnable;
private static final Object monitor = new Object();
static {
thread = new Thread(() -> {
while (true) {
synchronized (monitor) {
try {
monitor.wait();
} catch (InterruptedException e) {
e.printStackTrace();
continue;
}
if (runnable != null) {
runnable.run();
runnable = null;
}
}
}
});
thread.start();
}
public static void execute(Runnable runnable) {
AsyncExecutorWaitNotify.runnable = runnable;
synchronized (monitor) {
monitor.notify();
}
}}
ReentrantLock
public class AsyncExecutorLockCondition {
private static final ReentrantLock lock = new ReentrantLock();
private static final Condition cond = lock.newCondition();
private static Thread thread;
private static Runnable runnable;
static {
thread = new Thread(() -> {
while(true){
try {
lock.lock();
cond.await();
runnable.run();
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
public static void execute(Runnable runnable) {
AsyncExecutorLockCondition.runnable = runnable;
lock.lock();
cond.signal();
lock.unlock();
}}
答案 0 :(得分:1)
以上都不是。第三是最接近的方法,但仍然不是最佳方法。使用looper + handler或消息队列。另外,应该有一条消息可以发送给任何线程,告诉它退出循环并终止。否则,当不再需要它时,它将泄漏它可以引用的所有内存(这将是很多事情,因为它将对其父对象进行内部引用),但是无论如何它都会永久存在。请记住,线程直到退出之前都不会被GC。
答案 1 :(得分:1)
我个人不喜欢第一种方法,可能主要是因为interrupt
。如果有人以某种方式呼叫并中断该线程怎么办?您将运行一些任意代码,可能不是最好的主意。另外,当您中断时,实际上是在用异常链填充堆栈跟踪,这是抛出异常最昂贵的部分。
但是假设您不在乎第二点,而您完全可以控制第一点; IMO的这种方法可能没有什么问题。
现在,在此示例中,Conditional
和wait/notify
之间的差异很小。我不知道内部细节,哪些细节可能更快或更更好,但通常首选Conditional
;主要是因为它更容易阅读,至少对我而言。与Conditional
不同,synchronized
可以始终从不同锁中获取。
其他优点是(此处无关):您可以创建多个条件,从而仅唤醒所需的线程;不像notifyAll
。然后有一些到期的方法,例如awaitUntil(Date)
或await(long, TimeUnit)
或awaitNanos
。甚至有一种方法将await
忽略interrupts
:awaitUninterruptibly
。
话虽这么说,您不需要在lock::unlock
之后输入await
,因为有关此方面的文档非常清楚:
与此条件相关联的锁已自动释放...
一种更直接的方法是:
static class AsyncExecutor {
private static final ExecutorService service = Executors.newSingleThreadExecutor();
public static void execute(Runnable runnable) {
service.execute(runnable);
}
}