java - 等待/通知 vs sleep /中断 vs ReentrantLock.Condition

标签 java android multithreading thread-sleep reentrantlock

我正在编写一种“按类型搜索”机制 (android),它在后台线程中进行 sqlite 查询并将结果发回 UI 线程。理想情况下,线程应该等待/ sleep ,唤醒以执行任何接收到的 Runnable 对象并返回 sleep 。实现这一目标的最佳方式是什么?为什么?

基本上我想了解这 3 个选项之间的主要区别是什么,以及哪个最适合这个具体场景

  1. 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();
    }}
    
  2. 等待/通知

    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();
        }
    }}
    
  3. 重入锁

    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();
    }}
    

最佳答案

就我个人而言,我有点不喜欢第一种方法,可能主要是因为中断。如果有人、某事以某种方式调用并中断该线程怎么办?您将运行一些任意代码,这可能不是最好的主意。此外,当您中断时,您实际上是在用异常链填充堆栈跟踪,这是抛出异常的最昂贵的部分。

但是假设你不关心第二点,而你完全控制了第一点;在我看来,这种方法可能没有任何问题。

现在这个例子中Conditionalwait/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/

相关文章:

android - Dagger 2 androidx fragment 不兼容类型

java heap size error dex2jar android反编译解决方法?

java - 从 while 循环中启动线程,会发生什么?

java - 每当我单击“后退”/“主页”按钮时,代码的asynctask部分就会关闭/停止该应用程序

java - 是否可以在 JAXB 编码期间忽略包装类

java - 如何强制 hibernate 在 session 关闭时不保存和数据更新?

java - OutputStream 附加文件类型

java - start() 方法不存在

java - 无法解析构造函数

java - JVM 是 32 位还是 64 位?