简体   繁体   中英

Can't stop thread

I have these two methods for creating and stopping a thread. However the thread still keeps running, even after the first method is called. (I'm creating an object of the class and calling them from another class).

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

When stopAlarm is called the thread is always null, although it is called after triggerAlarm is called (thread is running).

Depending on your OS you may find making your thread volatile may fix this.

private volatile Thread thread;

However - there are better ways to do this. One very useful one is using a small (just one entry) BlockingQueue which is poll ed by the running thread.

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

Clearly you will have to manage edge cases like where someone calls stopAlarm when no alarm is running.

Your problem is caused by thread scope. Thread scope is created when you create a thread with same variables in the scope but you can't change these variables from outside world. Best practice for managing runnables in android is to use 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
    }
};

after definitions, in order to start the runnable:

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

in order to stop the runnable:

handler.removeCallbacks(alarmTest);

EDIT: wait statement with loop

EDIT: Complete solution

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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM