【问题标题】:Rerunning a thread重新运行线程
【发布时间】:2023-04-07 18:31:01
【问题描述】:

在我的安卓游戏中,我生成了一个单独的线程来播放soundpool 类的声音。每次我必须播放声音时,我都必须创建一个新线程并执行thread.start()。是否可以一次创建线程并重用?我想这样做是为了避免产生大量线程的开销。

【问题讨论】:

  • 不,一旦Thread 终止,您需要创建一个新的Thread 以重新运行Runnable 逻辑

标签: java android multithreading


【解决方案1】:

【讨论】:

    【解决方案2】:

    是否可以一次创建线程并重复使用?

    这是不可能的。

    可能的解决方案是使用固定大小的线程池(取决于您的要求)并通过将您的可运行任务提交到线程池来继续重用它。

    确定线程池的完美大小很重要,太少会出现类似问题,太高会出现性能问题。所以你需要做一些基准测试来确定相同的。一个更好的主意是使其可配置并对其进行监控。

    您可能想在 java 中查看 ExecutorServiceExecutors 以了解线程池。

    【讨论】:

    • 其实是可以的。如果您创建一个带有自己的 Looper 和 Handler 的 Thread 并启动它,它将等待消息和 runnables 并在它们到达时执行它们。
    【解决方案3】:

    您可以使用synchronizedwaitnotify 命令创建一个无限线程,每次触发它时都会播放您的声音。

    class InfininteTriggerableThread extends Thread {
    
    
        private volatile boolean paused = true;
        private final Object pauseObject = new Object();
    
    
        @Override
        public void run(){
            try {
                while(true){
                    while (paused) {
                        synchronized(pauseObject) {
                            pauseObject.wait();
                        }
                    }
                    // do your action here
                    paused = true;
                }
            } catch (InterruptedException e) { }
        }
    
    
    
        // trigger method
        public void trigger(){
            paused = false;
            synchronized(pauseObject) {
                pauseObject.notify();
            }
        }
    
    };
    

    【讨论】:

    • 如果您想知道处理器是否会在运行 while(true) 和 while(pause) 循环时做不必要的工作——不,它不会。线程将暂停,直到同步对象可用
    • 是的,当你在调用wait 之后调用notify 时,对象将被同步通知并且线程将退出synchronized 块。它将退出 while(paused) 并继续执行,正如我在代码中的 cmets 所示。
    • 其实这里不需要while(paused),你可以用if(paused)代替,但是while是传统的,更健壮。
    • 当然,只需修改触发方法,如果 paused == true,它会将 paused 设置为 false 并调用 notify,如果 paused == false,添加一些它接收的对象作为参数(例如你的声音),进入队列。所以在 run() 方法中它应该查看队列并播放每个声音,直到队列变空。
    • 我找到了另一种运行无限线程的方法,以便它可以一个一个地接收和执行runnables。方法是运行Looper.prepare(),然后创建一个处理程序,然后在这个新线程中运行Looper.loop()——这样runnables 可以被发送到这个特定的处理程序并在它所附加的线程中执行而不会丢失。明天我会带着例子回来(我也对这个话题感兴趣)
    【解决方案4】:

    正如我之前所承诺的,我测试了使用Looper的线程可以无限运行,并且可以接受Runnables来一一执行。

    // create a custom Thread class
    class ThreadWorking extends Thread {
    
        public volatile Handler handler;
    
        @Override
        public void run(){
            // between Looper.prepare() and Looper.loop() we need to create a handler
            // which will receive messages and runnables for this thread
            Looper.prepare();
            handler = new Handler();
            Looper.loop();
        }
    };
    
    // then create new thread and start it
    final ThreadWorking threadWorking = new ThreadWorking();
    threadWorking.start();
    Log.println(Log.DEBUG, "thread test", "New thread started");
    

    现在新线程正在循环中,可以通过其Handler 接收Messages 和Runnables。它们将存储在内部队列中,并在这个特定线程中一个接一个地执行。为了测试,我在按钮点击时发送Runnable

    threadWorking.handler.post(new Runnable(){
        @Override
        public void run() {
            try {
                 Log.println(Log.DEBUG, "thread test", "Executed: " + System.currentTimeMillis()/1000);
                 Thread.sleep(2000);
            } catch (InterruptedException e) { }
        }
    });
    

    在我启动一个应用程序并快速单击几次按钮后,日志显示如下:

    04-09 16:21:56.599: D/thread test(19264): New thread started
    04-09 16:21:59.569: D/thread test(19264): Executed: 1397046119
    04-09 16:22:01.569: D/thread test(19264): Executed: 1397046121
    04-09 16:22:03.569: D/thread test(19264): Executed: 1397046123
    04-09 16:22:05.569: D/thread test(19264): Executed: 1397046125
    04-09 16:22:07.569: D/thread test(19264): Executed: 1397046127
    04-09 16:22:09.569: D/thread test(19264): Executed: 1397046129
    

    所以一切都按预期正常工作,没有冻结 UI 或创建额外的线程。

    【讨论】:

    • 我知道这个新线程将处于无限循环中,直到循环停止。当这个looper在执行了一些之后没有收到新的runnables时会发生什么。它会在不消耗资源的情况下保持低位还是会影响性能?
    • 查看与 Java Looper 不同的 Looper 类的 Android 实现,我发现 loop() 方法只是启动无限 for (;;) 循环,在该循环中要求队列提供新消息。真诚地,我不知道它会如何影响性能,因为我对 Dalvik JVM 内部程序和优化没有那么深入。但我认为它应该比每次都创建一个新线程更好——只是因为创建一个新线程的所有操作都是在 UI 线程中进行的,因此对它的影响要大得多。
    • 无限循环将消耗资源,除非它的实现类似于您之前使用通知和等待的答案。
    • 当然!但它更容易实现,因为您不需要设计任务队列的内部机制。
    • 我认为我们可以在这个例子中使用通知和等待来获得两全其美。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多