无法停止线程

时间:2016-12-27 14:17:32

标签: java android multithreading

我有两种创建和停止线程的方法。但是,即使在调用第一个方法之后,线程仍然保持运行。 (我正在创建类的对象并从另一个类中调用它们。)

private Thread thread;

public void stopAlarm() {
    Log.i(LOG_TAG, "stopAlarm called");
    sendAlarm = false;
    if (!thread.equals(null)) {
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


public void triggerAlarm() {
    Runnable alarmTest = new Runnable() {
        @Override
        public void run() {
            while (sendAlarm) {
                Log.i(LOG_TAG, String.valueOf(sendAlarm));
            }
        }
    };
    thread = new Thread(Test);
    thread.start();
}

当调用stopAlarm时,线程始终为null,尽管在调用triggerAlarm(线程正在运行)之后调用它。

2 个答案:

答案 0 :(得分:1)

根据您的操作系统,您可能会发现让您的帖子volatile可以解决此问题。

private volatile Thread thread;

但是 - 有更好的方法可以做到这一点。一个非常有用的方法是使用一个小的(只有一个条目)BlockingQueue,它由正在运行的线程poll编写。

// Use a BlockingQueue to signal the alarm to stop.
BlockingQueue<String> stop = new ArrayBlockingQueue<>(1);

public void stopAlarm() {
    stop.add("Stop");
}


public void triggerAlarm() {
    new Thread(() -> {
        try {
            while (stop.poll(1, TimeUnit.SECONDS) == null) {
                // Stuff
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
}

显然,您必须管理边缘情况,例如在没有警报运行时有人呼叫stopAlarm的情况。

答案 1 :(得分:1)

您的问题是由线程范围引起的。当您在范围中创建具有相同变量的线程时,会创建线程范围,但您无法从外部世界更改这些变量。在android中管理runnables的最佳做法是使用Handler

Handler handler = new Handler();
Runnable alarmTest = new Runnable() {
    @Override
    public void run() {
        Log.i(LOG_TAG, String.valueOf(sendAlarm));
        handler.post(alarmTest, 5000); //wait 5 sec and run again
        //you can stop from outside
    }
};

定义之后,为了启动runnable:

handler.post(alarmTest,0); //wait 0 ms and run

为了停止runnable:

handler.removeCallbacks(alarmTest);

编辑:带循环的等待语句

编辑:完整的解决方案

Handler handler = new Handler();
Runnable alarmTest = new Runnable() {
    @Override
    public void run() {
        Log.i(LOG_TAG, String.valueOf(sendAlarm));
        handler.post(alarmTest, 5000); //wait 5 sec and run again
        //you can stop from outside
    }
};

public void stopAlarm() {
    Log.i(LOG_TAG, "stopAlarm called");
    handler.removeCallbacks(alarmTest);
}


public void triggerAlarm() {
    handler.post(alarmTest,0); //wait 0 ms and run
}