I have a worker Thread with a Handler associated with it. The Handler receives Messages and perform some operations in the worker Thread. I would like to "stop" the Thread in onPause() of my Activity. In the onPause() method of my Activity, i send a quit message to my Handler so that my worker Thread will break out of Looper.loop() and return from run().
Is this the correct way to stop a Thread? If not, how should it be done?
I have seen code examples calling t1.join() from the main Thread where t1 is their worker Thread.
What is the purpose of join()?
Do i need to do a join() in my example?
My worker Thread:
class WorkerThread extends Thread {
private static final int QUIT = -1;
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// do stuff
if(msg.what == QUIT){
Looper.myLooper().quit();
}
// do stuff
}
};
Looper.loop();
}
}
I have not worked on android but in java a thread can be stopped in following ways -
Use a volatile Boolean flag - Use this flag in loop(while(flag)). Which keeps running till the flag is true. If you want to stop thread set flag to false.
Checking for interrupt flag- You have static Boolean method in thread class as Thread.interrupted() which checks for interrupt flag. You can interrupt a waiting thread by calling Thread.interrupt().
Join() method - the Join method makes the current thread to wait for a thread to die. This is used in the case when you have some logic which is to be executed only after a thread completes its execution. So you can't use join to stop a thread but make a thread to wait for another thread completion.
Hope it helps. Thanks
Related
I'm trying to create a Runnable that keeps running, but I need to makes changes to a variable from outside, to pause or resume the work that the Runnable is doing.
This is my Runnable implementation:
private boolean active = true;
public void run() {
while (true) {
if (active) { //Need to modify this bool from outside
//Do Something
}
}
}
public void setActive(boolean newActive){
this.active = newActive;
}
In my main class I call:
Thread thread = new Thread(myRunnable);
thread.run();
myRunnable.setActive(false); //This does not work!!!
//The boolean remains true inside myRunnable.
I've tried with the "volatile" modifier on active, but still it won't update. Any ideas are greatly appreciated.
Thread thread = new Thread(myRunnable);
thread.run();
myRunnable.setActive(false);
The third line will only execute after the run() method has returned. You are executing everything in a single thread, sequentially. The second line should be
thread.start();
And the field should be volatile.
Note, however, that setting the active field to false will make the thread enter a busy loop doing nothing, but consuming CPU by looping constantly. You should rather use a lock to wait until you can resume.
I am using Threads (still..) for many stuff right now. I found many methods of thread that I would most likely use marked as deprecated.
Is there any chance to pause/resume thread with some triggers? Most people say to use wait.. but if I don't know the time ? I have some events that can happen after 5 minutes or after 2 hours...
Also .. another thing.
If I have a Thread .. it has an run() method. Now the Thread is started , run does what it has to do and then the Thread dies. Like forever ? The stuff from run() method is done so the Thread is ready to be taken out by garbage collector or is it just in some phase of disabled but still existing ?
Now you have a run method like that :
public void run(){
while(running){
//do stuff...
}
}
If I switch the running to false, run method loops and stops because there is nothing more to do . Does this thread also die ? Can I for example say after some time I want to rerun this thread, so I just set the running to true again and call the run method, or do I have to recreate the Thread once again ?
A Thread can only "live" once. When you create a Thread, you specify a Runnable instance as a target (if you don't, the thread targets itself—it implements Runnable and its default run() method does nothing). In either case, when the thread completes the run() method of its target Runnable, the thread dies.
In the example posed in the question, setting running to true after the run() method has returned will do nothing; the Thread can't be restarted after dying.
If you want to pause a thread, and reuse it later, there are a number of mechanisms. The most primitive is wait() and notify(). Rather than waiting for a specified period of time, you wait until a condition changes, like this:
abstract class Pausable implements Runnable {
private final Object lock = new Object();
private boolean pause = false;
abstract void doSomething();
#Override
public void run() {
while (cantering()) doSomething();
}
private boolean cantering() {
synchronized (lock) {
while (pause) {
try { lock.wait(); }
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
return false;
}
}
}
return true;
}
final void whoa() {
synchronized(lock) {
pause = true;
}
}
final void giddyup() {
synchronized(lock) {
pause = false;
lock.notify();
}
}
}
That's a lot of code, and it's fragile. I've been writing Java for 20 years and I'm not sure I got it right. That's why you should use the right tool from java.util.concurrency. For example, if you are waking up the thread to process a message, use a BlockingQueue, and let the consuming thread wait for messages to arrive on the queue. If you have tasks you want to perform asynchronously in response to some event, create an ExecutorService and submit the tasks. Even if you do want to use something like wait()/notify(), the concurrency package's Condition class gives you a lot more control over locking than intrinsic locks offer.
Can I [...] and call the run method?
If you have a Thread t = ...;, and you write a call to t.run(), you probably are making a mistake.
A Thread is not a thread. A thread is a path of execution through your code. A Thread is an object with methods that can be used to create a new thread and manage its life-cycle.
You create the new thread by calling t.start().
Remember this mantra:
The start() method is the method that the library provides for your code to call when you want to start a new thread.
The run() method is the method that your code provides for the library to call in the new thread.
i have a main thread in my app and inside this main thread i create another thread, let's say it is named named "WorkerThread".
The WorkerThread has an infinite loop that does some database search and eventually communicates via Serial Port with a thermal printer.
But when the user closes the application, it remains alive because the thread is still running.
I know i can just set my thread as daemon, which means the thread will stop when the application closes, but also i know that this may cause IO errors.
So, what is the most efficient way of achieving this behavior in a non-daemon thread?
Add the boolean flag to stop your thread on application exit.
public class WorkerThread extends Thread {
private boolean running = false;
#Override
public void run() {
while (running) {
// do smth
}
}
#Override
public void start() {
setRunning(true);
super.start();
}
#Override
public void setRunning(boolean value) {
this.running = running;
}
}
To stop the thread, call workerThread.setRunning(false).
Use some kind of flag (boolean?) to signal your worker thread to stop after finishing what it is processing right now.
You should interrupt it from the main thread using Thread.interrupt(). In the worker thread, on each loop iteration, it should check for the return of workerThread.interrupted() and if it is true then clean up and return.
Check the documentation, cause blocking methods like wait() will throw an InterruptedException you might have to evaluate.
can someone explain what what is going on here for which thread is being blocked? the thread object here is used for canvas and drawing graphics, the join() method is called on this graphics thread so it will continue to finish. while the other thread is blocked and waiting. which thread is this?
if the surfaceView class is running on the main UI thread than the UI will be blocked waiting for the graphics thread to finish. this does not make sense. so the other explanation would be for there to be three separate threads here. the main UI thread, the graphics thread where join() is being called on, and a third thread for surface view that is getting blocked while the graphics thread finishes
is there in fact three threads running, and the UI thread is not the one being blocked?
nowhere in my code did I start a new thread for SurfaceView. I only instantiated a SurfaceView object.
as this code is written it looks like the main UI thread is blocked waiting for the graphics thread to finish.
If the SurfaceView object is instantiated inside of a thread or AsyncTask then it would look more clear.
// this code is located inside of the SurfaceView class
#Override
public void surfaceCreated(SurfaceHolder holder) {
// can also put this code in surfaceChanged
running = true;
thread = new Thread(surfaceRunnable);
thread.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
running = false;
boolean retry = true;
while(retry) {
try {
thread.join();
retry = false;
} catch( InterruptedException e) {
}
}
The thread that is blocked is the UI thread. Proving this with a debugger is a good idea. You can confirm this by viewing the source code of SurfaceView.java (if in Eclipse, hit F3 while the cursor is on the text SurfaceView). In particular:
The callbacks such as surfaceDestroyed() are called from SurfaceView.updateWindow():
private void updateWindow(boolean force, boolean redrawNeeded) {
...
callbacks = getSurfaceCallbacks();
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
}
updateWindow() is called from the anonymous class derived from Handler and assigned to mHandler:
final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case KEEP_SCREEN_ON_MSG: {
setKeepScreenOn(msg.arg1 != 0);
} break;
case GET_NEW_SURFACE_MSG: {
handleGetNewSurface();
} break;
case UPDATE_WINDOW_MSG: {
updateWindow(false, false);
} break;
}
}
};
Note that this mHandler object is constructed when the SurfaceView object is constructed, which happens on the UI thread. And note that the Handler constructor binds the Handler to the Looper associated with the current thread (the UI thread). So handleMesssage() runs on that Looper which is the UI thread's Looper. Thus, updateWindow() is called on the UI thread.
updateWindow() is also called several other times in the file and most of the time it is easy to deduce that it is being called from the UI thread.
I'm actually in need of waiting for the ui thread to execute a runnable before my application thread can continue. Is the wait()/notify() way a proper way to do it or is there something better for this? What I'm actually doing looks like this:
public void showVideoView() {
try {
final AtomicBoolean done = new AtomicBoolean(false);
final Runnable task = new Runnable() {
#Override
public void run() {
synchronized(this) {
mStartupCurtain.setVisibility(View.GONE);
mVideoView.setVisibility(View.VISIBLE);
mWebView.loadUrl("about:blank");
mWebView.setVisibility(View.GONE);
done.set(true);
notify();
}
}
};
mUiHandler.post(task);
synchronized(task) {
while(!done.get()) {
task.wait();
}
Log.d(TAG, "showVideoView done!");
}
} catch (InterruptedException e) {
Log.e(TAG, "Thread got interrupted while waiting for posted runnable to finish its task");
}
}
Also when I do this I have to be sure that the thread is not the one of the UI, which happens when I start calling methods from a listener method coming from an interface like MediaPlayer.OnCompletionListener.
What do you think?
Looks fine to me.
The "done" variable could be a regular Boolean instead of AtomicBoolean since you definitively get/set it's value within the lock. I like that you check the value of "done" prior to calling wait - since it is quite possible the task will have been completed before you ever enter the lock in the worker thread. If you had not done that, the wait() call would go indefinitely since the notify() had already happened.
There is one edge case to consider that may or may not be applicable to your design. What happens if the UI thread is attempting to exit (i.e. app exit) when the worker thread is still stuck waiting for the task to complete? Another variation is when the worker thread is waiting on the task to complete, but the UI thread is waiting on the worker thread to exit. The latter could be solved with another Boolean variable by which the UI thread signals the worker thread to exit. These issues may or may not be relevant - depending on how the UI is managing the thread to begin with.
Use AsyncTask!
AsyncTask enables proper and easy use of the UI thread. This class
allows to perform background operations and publish results on the UI
thread without having to manipulate threads and/or handlers.
http://developer.android.com/reference/android/os/AsyncTask.html
Function:
public static void postOnUI(Runnable runnable,boolean wait) {
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
// Is on UI thread.
runnable.run();
return;
}
Handler uiHandler = new Handler(Looper.getMainLooper());
AtomicBoolean done = new AtomicBoolean(false);
uiHandler.post(() -> {
runnable.run();
done.set(true);
});
if (wait) {
while (!done.get()) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
}
}
}
Usage Example:
Utils.postOnUI(headerView::updateUI,true);