【问题标题】:How to Stop/Wait a Thread and then Resume/Restart it later如何停止/等待线程,然后再恢复/重新启动它
【发布时间】:2026-01-08 15:50:01
【问题描述】:

我正在后台运行一项服务,该服务也绑定到一个活动,以向视图提供一些数据结果。 所以我的服务在后台运行,我在我的活动开始时绑定服务,并在它关闭时解除绑定,而不管我的后台服务是否不断运行。 当我的活动第一次开始时,首先触发此服务。

现在我在服务中创建了两个线程。一个用于后台工作。其他线程“displayThread”用于获取数据并将数据推送到活动。

现在我的显示线程是这样的:

Thread displayThread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                executeDisplayQueue();
            } catch (InterruptedException e){
                displayThread.interrupt();
            }
        }
});

因此,当我的活动开始时,我的服务开始,并且我正在启动两个线程:

@Override
public void onCreate() {
    super.onCreate();
    Log.d(LOG_TAG, "Creating Service......");
    thread.start();
    displayThread.start();
    Log.d(LOG_TAG, "Service is created.");
}

现在我想要的是,当我在 Activity 关闭时解除绑定我的服务时,我的“displayThread”会停止或暂停,并在再次启动调用 rebind() 函数的 Activity 时重新启动或恢复。

@Override
public boolean onUnbind(Intent intent) {
    super.onUnbind(intent);
    // Stop/Pause/Wait my displayThread here
    return true;
}

@Override
public void onRebind(Intent intent) {
    super.onRebind(intent);
    // Restart/Resume my displayThread here
    Log.d(LOG_TAG, "trying to check display thread");
}

请帮助我,因为我尝试了很多东西。 现在 displayThread.wait() 暂停了我的应用程序屏幕,所以它变黑了,好像一切都停止了,这当然不是正确的方法。

请给我一个关于如何进一步进行的解决方案。

编辑

这是executeDisplayQueue()函数:

@Override
    protected void executeDisplayQueue() throws InterruptedException {
        Log.d(LOG_TAG, "Starting execution of queue...");
        while (!Thread.currentThread().isInterrupted()) {
            SomeJob job = null;
            try {
                job = jobShowQueue.take();
                Log.d(LOG_TAG, "Taking Job no. " + job.getId() + " from the queue...");
                if (job.getJobState().equals(JobState.NEW)) {
                    Log.d(LOG_TAG, "Job state is NEW.");
                    job.setJobState(JobState.RUNNING);
                    job.getCmd().run(bluetoothSocket.getInputStream(), bluetoothSocket.getOutputStream());
                } else {
                    Log.e(LOG_TAG, "Job state is not NEW and therefore it should not be in Queue");
                }
            } catch (InterruptedException ie){
                Thread.currentThread().interrupt();
            } catch (UnsupportedCommandException u) {
                if (job != null)
                    job.setJobState(JobState.NOT_SUPPORTED);

            } catch (IOException ioe){
                job.setJobState(JobState.BROKEN_PIPE);

                Log.e(LOG_TAG, "Broken Pipe Error. Close the connection and restart again: "+ioe.getMessage());
            } catch (Exception e){
                job.setJobState(JobState.EXECUTION_ERROR);
                Log.e(LOG_TAG, "Failed to run Command. Error: "+e.getMessage());
            }
            if (job != null){
                Log.d(LOG_TAG, "Job is Finished.");
                final SomeJob finalJob = job;
                ((Activity) applicationContext).runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        ((Activity) applicationContext).stateUpdate(finalJob);
                    }
                });
            }
        }
    }

所以基本上我是从队列中一个一个地取出作业并将其填充到活动中。所以当我的活动关闭时,我希望这个线程(displayThread)停止,因为它不再需要填充任何东西。当它再次打开时,我的 displayThread 应该会自行重启。

【问题讨论】:

    标签: java android multithreading service


    【解决方案1】:

    您可以使用线程锁。方法“executeDisplayQueue”中是否有while循环?您可能应该将 if(){lock.wait()} 放在 while 循环中。

    private final Object displayThreadLock = new Object();
    private boolean mIsBound;
    
    Thread displayThread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized(displayThreadLock) {
                    if (!mIsBound) {
                        displayThreadLock.wait(); // this thread will wait here util displayThreadLock.notify() is called
                    }
                    try {
                        executeDisplayQueue();
                    } catch (InterruptedException e){
                        displayThread.interrupt();
                    }
                }
            }
    });
    
    @Override
    public boolean onUnbind(Intent intent) {
        super.onUnbind(intent);
        // Stop/Pause/Wait my displayThread here
        mIsBound = false;
        return true;
    }
    
    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        // Restart/Resume my displayThread here
        mIsBound = true;
        synchronized(displayThreadLock) {
            displayThreadLock.notify(); // call notify to break the wait, so the displayThread continues to run
        }
        Log.d(LOG_TAG, "trying to check display thread");
    }
    

    【讨论】:

    • 当我使用上述方法时,在onRebind(Intent intent) 中调用displayThreadLock.notify(); 时出现错误,这是错误:java.lang.RuntimeException: Unable to bind to service com.zymbia.app4.services.SomeService@2c0e85b4 with Intent { cmp=com.zymbia.app4/.services.SomeService }: java.lang.IllegalMonitorStateException: object not locked by thread before notify()
    • 否 它工作正常。我刚刚更改了 onRebind() :synchronized (displayThreadLock){ displayThreadLock.notify(); } 现在它工作得很好。非常感谢@wrkwrk 的回答。
    【解决方案2】:

    由于您的 displayThread 中有一个用于 InterruptedException 的 try-catch 块,您可以通过以下方式停止线程:

    displayThread.interrupt();
    

    并且在重新绑定时再次启动 displayThread:

    displayThread.start();
    

    对了,能不能展示一下executeDisplayQueue()的方法体?我需要知道这对你来说是否安全。

    您需要处理一个额外的问题。在 displayThread 被中断后,这意味着您的活动不再存在,您无法为其安排作业。

    【讨论】:

    • 上述方法已被 Google 弃用。
    • @AnggrayudiH 我只知道 Thread.stop() 和 Thread.resume() 已被弃用,但 Thread.interrupt() 应该没问题。您在哪里读到上述方法已被弃用?
    • 如果您拥有 Android 6.0 的最新文档,并且您将目标和编译 SDK 设置为 API 23,您可以看到该 interrupt() 方法已被弃用。
    • 6.0还没试过,让我看看。谢谢。
    • 天啊,你是对的,interrupt() 方法没有被弃用!
    最近更新 更多