当前位置: 首页 > 面试题库 >

如何确保另一个线程的处理程序在调用之前不为null?

荆学民
2023-03-14
问题内容

前几天,当我的程序尝试使用在另一个线程上创建的处理程序向该线程发送消息时,抛出NullPointerException。尽管调用线程已经在另一个线程上调用了start,但是尚未创建另一个线程创建的处理程序,或者该调用程序尚未看到该线程。这种情况很少发生。几乎每个测试运行都不会获得异常。

我想知道最好的方法是以最小的复杂性和性能损失来确保避免此问题。该程序是一款游戏,对性能非常敏感,尤其是在运行后。因此,例如,我尝试避免在设置后使用同步,并且希望避免随时在变量上旋转。

背景:
在Android中,Handler类可用于“使要在与您自己的线程不同的线程上执行的动作排队”。此处的文档: http
//developer.android.com/intl/de/reference/android/os/Handler.html

必须在将使用处理程序的线程上创建处理程序。因此,在创建该线程的线程运行的线程的构造函数中创建它不是一种选择。

当处理程序用于UI线程以外的其他线程时,还必须使用Looper类: http
//developer.android.com/intl/de/reference/android/os/Looper.html

该文档给出了使用两个类实现此目的的示例:

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }
}

我目前非常丑陋的解决方法如下所示:

public class LooperThread extends Thread {

    public volatile Handler mHandler;

    public final ArrayBlockingQueue<Object> setupComplete = new ArrayBlockingQueue<Object>(1);

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        setupComplete();

        Looper.loop();
    }

    public void waitForSetupComplete() {
        while ( true ) {
            try {
                setupComplete.take();
                return;
            } catch (InterruptedException e) {
                //Ignore and try again.
            }
        }
    }

    private void setupComplete() {
        while( true ) {
            try {
                setupComplete.put(new Object());
                return;
            } catch (InterruptedException e) {
                //Ignore and try again.
            }        
        }
    }

}

创建线程中的代码如下所示:

    LooperThread otherThread = new LooperThread();
    otherThread.start();        
    otherThread.waitForSetupComplete();
    otherThread.mHandler.sendEmptyMessage(0);

有更好的解决方案吗?谢谢。


问题答案:

准备一个Looper罐头块一段时间,所以我想您遇到了prepare()需要花点时间才能完成的情况,因此mHandler仍然不确定。

您可以进行Thread扩展HandlerThread,即使那样,您仍然必须等待以确保Looper已初始化。也许这样的事情可能会起作用,您可以Handler单独定义,但要使用Looper自定义线程。

也许。

private void setUp() {
    mHandlerThread = new CustomThread("foo", Process.THREAD_PRIORITY_BACKGROUND);
    mHandlerThread.start();

    // Create our handler; this will block until looper is initialised
    mHandler = new CustomHandler(mHandlerThread.getLooper());
    // mHandler is now ready to use
}

private class CustomThread extends HandlerThread {
    public void run() {
        // ...
    }
}

private class CustomHandler extends Handler {
    CustomHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        // ...
    }
}


 类似资料:
  • 当我呈现视图时,是,因为是我这样插入它。 如果我提交表单,我将执行以下处理程序: 所以基本上我总是要添加一个`stopmessage,不管是成功还是失败。 如何检索设置到另一个处理程序中的属性值?用胸腺嘧啶有可能吗? 注意:暂时,我将设置为控制器类的一个字段,并在处理程序周围设置/not null,以便始终能够看到它的值。这是一个解决办法,但似乎不是正确的做法。因为我是个新手,所以我很乐意听到处理

  • 问题内容: 假设我有一个事件处理程序,它对服务器进行了两次AJAX调用: 我意识到,调用回调的顺序是不确定的,因为它取决于每个请求花费的时间等。 但是,这是我的问题:是否可以保证在调用两个回调函数之前到达事件处理程序的末尾?我已经读过页面的所有Javascript都在一个线程中执行,因此我认为这意味着在可以调用任何回调之前,一定要完成我的事件处理程序。 这样对吗?还是有可能第一个请求可能已经完成,

  • 问题内容: 我有以下结构: 该方法 可以 被许多线程同时调用。该 会 抛出异常(它在后台,可能成为过时的使用一些数据)。 如果引发异常,则执行一些耗时的任务,比如说“更新”所有当前数据,并且我可以调用。 问题: 如何确保只调用 一次 ?如果我在的条目中放置了原子标志,则不能确定何时清除该标志。 我该如何解决?请注意:由于它是一个外部API,因此我无法修改,并且我正在使用装饰器模式来使用它。 问题答

  • 问题内容: 我在掌握如何正确处理从以多线程方式使用Boost Asio的多线程程序创建子进程方面遇到一些麻烦。 如果我理解正确,那么在Unix世界中启动子进程的方法是先调用,然后调用。另外,如果我理解正确,则调用将复制所有文件描述符,依此类推,除非标记为,否则需要 在子进程中将其 关闭(从而在调用时被原子关闭)。 Boost Asio需要在被调用时得到通知,以便通过调用正确运行。但是,在多线程程序

  • 我正在使用Google Maps V2 API开发一个简单的应用程序,只是为了获得基本知识,我面临着这个错误: 奇怪的是,我可以在我的模拟器(API16)上运行这个应用程序,它运行得很好,但当我试图在物理设备(API15)上运行它时,它得到了这个错误。AsyncTask在单独的类中运行,因此可能会导致此问题。如果有任何建议,我将不胜感激。提前谢了。

  • 问题内容: 我在Java中的线程上有些挣扎,我有三个线程- 线程1,线程2和线程3。那些启动时正在执行某些任务,我想通过thread1停止这两个线程。我将thread1放在,然后停止两个线程,但是两个线程的进程仍在运行。你有什么想法吗? 问题答案: 您如何试图阻止他们??警告此方法已弃用。 而是考虑对线程1使用某种标志来与线程2和3通信,它们应该停止。实际上,您可能会使用interrupts。 下