我正在编写一种“按类型搜索”机制 (android),它在后台线程中进行 sqlite 查询并将结果发回 UI 线程。理想情况下,线程应该等待/ sleep ,唤醒以执行任何接收到的 Runnable 对象并返回 sleep 。实现这一目标的最佳方式是什么?为什么?
基本上我想了解这 3 个选项之间的主要区别是什么,以及哪个最适合这个具体场景
sleep /中断
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(); } }}
重入锁
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(); }}
最佳答案
就我个人而言,我有点不喜欢第一种方法,可能主要是因为中断
。如果有人、某事以某种方式调用并中断该线程怎么办?您将运行一些任意代码,这可能不是最好的主意。此外,当您中断时,您实际上是在用异常链填充堆栈跟踪,这是抛出异常的最昂贵的部分。
但是假设你不关心第二点,而你完全控制了第一点;在我看来,这种方法可能没有任何问题。
现在这个例子中Conditional
和wait/notify
之间的差别很小。我不知道内部细节以及哪个可能更快或更好,但一般来说 Conditional
是首选;主要是因为它更容易阅读,至少对我而言。此外,Conditional
可以一直从不同的 锁中获取,这与synchronized
不同。
其他优点是(此处无关):您可以创建多个条件,从而只唤醒您想要的线程;例如,与 notifyAll
不同。然后是具有到期时间的方法,例如 awaitUntil(Date)
或 await(long, TimeUnit)
或 awaitNanos
。甚至还有一种方法可以await
并完全忽略interrupts
:awaitUninterruptibly
。
据说在 await
之后你不需要 lock::unlock
因为文档在这方面非常清楚:
The lock associated with this Condition is atomically released ...
一个更直接的方法是:
static class AsyncExecutor {
private static final ExecutorService service = Executors.newSingleThreadExecutor();
public static void execute(Runnable runnable) {
service.execute(runnable);
}
}
关于java - 等待/通知 vs sleep /中断 vs ReentrantLock.Condition,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52555846/