Java 等待/通知vs睡眠/中断vs重入锁定状态
我正在编写一个随键入搜索机制(android),它在后台线程中进行sqlite查询,并将结果发布回UI线程。理想情况下,线程应该等待/睡眠,醒来执行任何接收到的可运行对象,然后返回睡眠状态。实现这一目标的最佳方式是什么?为什么 基本上,我想了解这3个选项之间的关键区别是什么,以及哪一个最适合这个具体场景Java 等待/通知vs睡眠/中断vs重入锁定状态,java,android,multithreading,thread-sleep,reentrantlock,Java,Android,Multithreading,Thread Sleep,Reentrantlock,我正在编写一个随键入搜索机制(android),它在后台线程中进行sqlite查询,并将结果发布回UI线程。理想情况下,线程应该等待/睡眠,醒来执行任何接收到的可运行对象,然后返回睡眠状态。实现这一目标的最佳方式是什么?为什么 基本上,我想了解这3个选项之间的关键区别是什么,以及哪一个最适合这个具体场景 睡眠/中断 public class AsyncExecutorSleepInterrupt { private static Thread thread; private static Run
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();
}}
以上都没有。第三种方法是最接近的,但仍然不是最好的方法。使用looper+处理程序或消息队列。另外,应该有一条消息可以发送给任何线程,告诉它退出循环并终止。否则,当不再需要它时,你将泄漏它可以引用的任何内存(这是一个很大的问题,因为它将有一个对其父级的内部引用),但无论如何,它将永远存在。请记住,线程在退出之前是不会被GCed的。就我个人而言,我有点不喜欢第一种方法,可能主要是因为
中断。如果有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人,有人?您可能会运行一些任意代码,这可能不是最好的主意。此外,当您中断时,您实际上是在用异常链填充堆栈跟踪,这是抛出异常最昂贵的部分
但是假设你不关心第二点,你完全控制了第一点;这种方法可能没有什么问题
现在,在本例中,Conditional
和wait/notify
之间的差异非常小。我不知道内部细节,也不知道哪种可能更快或更好,但一般来说,Conditional
是首选;主要是因为它更容易阅读,至少对我来说是这样。另外,与同步
不同的是,条件
可以始终从不同的锁中获取
其他优势(这里不相关):您可以创建多个条件,从而只唤醒您想要的线程;例如,与notifyAll
不同。还有一些过期的方法,比如waituntil(Date)
或wait(long,TimeUnit)
或waitnanos
。甚至有一种方法可以等待
并忽略中断
,不间断地等待
也就是说,您不需要在wait
之后使用lock::unlock
,因为文档在这方面非常清楚:
与此条件关联的锁已自动释放
更直接的方法是:
static class AsyncExecutor {
private static final ExecutorService service = Executors.newSingleThreadExecutor();
public static void execute(Runnable runnable) {
service.execute(runnable);
}
}
我认为向只执行此操作的线程添加循环器是一种资源浪费,最多浪费100个字节。活套不是重量级物体。我对活套很熟悉,但有一点不清楚。它是无限循环还是休眠/等待下一条消息?它休眠。基本上,它会在一个同步的堆栈上等待一条消息。如果您想要最简单的实现,HandlerThread基本上会为您设置所有这些。Re,“理想情况下,线程应该等待/睡眠,唤醒以执行任何接收到的可运行对象,然后返回睡眠。”您所描述的正是ThreadPoolExecutor
中的工作线程所做的。@通过这种方式,两个连续调用将在两个不同的线程上执行,不是吗?我不知道“这种方式”是什么意思。我想说的是,您的三个示例看起来都像是在尝试重新创建java.util.concurrent.ThreadPoolExecutor
类已经为您做的事情。;如果将ThreadPoolExecutor
配置为只有一个工作线程,则可以保证提交的任务将按照提交的顺序逐个执行。静态函数java.util.concurrent.Executors.newSingleThreadExecutor()
就是为了这个目的而存在的。