Main thread: can runnables be preempted? - java

I've a runnable instance that self-schedules itself again at the end of its run method:
private class MyRunnable implements Runnable {
private volatile boolean cancelled = false;
private Handler handler;
public MyRunnable(Handler h){
handler = h;
}
#Override
public void run(){
//Do stuff
if(!cancelled){
//Preemtion possible here?
handler.postDelayed(this, 1000);
}
}
public void selfStart(){
cancelled = false;
handler.removeCallbacks(this);
handler.post(this);
}
public void selfCancel(){
cancelled = true;
handler.removeCallbacks(this);
}
}
The runnable is first scheduled in the main thread calling selfStart from an activity's onStart.
At the same time, the runnable can be externally cancelled (calling selfCancel) from the activity's onStop and also from a Broadcast Receiver.
AFAIK Runnable.run, Activity.onStop and BroadcastReceiver.onReceive run in the same thread (the main one), so at first glance I thought there would be no thread-safety issues.
But it looks like sometimes, the runnable is being preemted in the middle of its run call, then it is cancelled from the activity or receiver, and then it resumes and re-schedules itself again.
Is this possible?
UPDATE:
I'll try to explain better the issue. The class shown above is intended to run tasks periodically in the main thread. In the "do stuff" comment there's actually code that updates a TextView with a value passed to the MyRunnable constructor. The activity cancels the current runnable and starts a new one when certain intents are received. Despite the current runnable is always requested to cancel itself before the new one is created, sometimes it is being left running along with the new one, so the text view is showing alternating values. This is not the intended behavior.
I thought if the runnable was currently running in the main thread, it would run until completion, and then other runnables or event handlers would be taken out of the queue and executed if needed, but no pending event or runnable could be "half executed".
There are two kinds of tasks running in the main thread that are related to the problem:
R1: The MyRunnable self-scheduling task. Runs and then it self-posts itself again with a delay of 1s.
R2: The event handlers that request cancellation of the current MyRunnable instance and create a new R1'. These happen randomly and are executed only once.
I've contemplated two scenarios. The first one:
R1 is already running in the main thread.
R2 arrives and is enqueued in the main thread.
R1 finishes running and posts itself again.
R2 runs and removes callbacks for R1.
R1 should never run again.
And the second one:
R1 is not running but is scheduled.
R2 arrives and removes callbacks for R1.
R1 should never run again.
Theoretically, if there's no preemtion, and there's only a single thread, how comes sometimes there are two R1s in the main thread?

As you have no synchronization on selfStart or selfCancel this is entirely possible.
An unreleated note, selfCancel could be called on a separate thread after your if statement in your run method has checked the value of cancelled. MyRunnable would then get one more call to run, which would end immediately as it's been cancelled.

My suggestion would be to move the //Do stuff inside the canceled check.
This avoids the race regardless of assumptions about which thread things are running on.
#Override
public void run(){
if(!cancelled){
//Do stuff
handler.post(this);
}
}
In general for maintainability, try to write code that works correctly regardless of the thread it is being run on. You never know when somebody will call selfCancel() on some other thread later thinking it is okay, when you have assumed they won't do that.

Well as others have said, there's no way a runnable can be preempted in a single thread. I also thought this idea was absurd. Shame on me for coming up with that nonsense.
There was nothing wrong with the runnables themselves. They were launched in the activity's onStart, and cancelled from Intents received by the activity, or in the activity's onStop. An this is the root of the problem: assuming onStart and onStop would run in a predictable order. Sometimes when coming back to the activity, a second onStart was executed before the first activity's onStop. Two tasks were running and the thing messed up to a point where the first task was never terminated.
Ensuring no task is launched without previous termination of the current one solved the issue.

Related

Java multithreading error [duplicate]

The following code leads to java.lang.IllegalThreadStateException: Thread already started when I called start() method second time in program.
updateUI.join();
if (!updateUI.isAlive())
updateUI.start();
This happens the second time updateUI.start() is called. I've stepped through it multiple times and the thread is called and completly runs to completion before hitting updateUI.start().
Calling updateUI.run() avoids the error but causes the thread to run in the UI thread (the calling thread, as mentioned in other posts on SO), which is not what I want.
Can a Thread be started only once? If so than what do I do if I want to run the thread again? This particular thread is doing some calculation in the background, if I don't do it in the thread than it's done in the UI thread and the user has an unreasonably long wait.
From the Java API Specification for the Thread.start method:
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
Furthermore:
Throws:
IllegalThreadStateException - if the thread was already started.
So yes, a Thread can only be started once.
If so than what do I do if I want to
run the thread again?
If a Thread needs to be run more than once, then one should make an new instance of the Thread and call start on it.
Exactly right. From the documentation:
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
In terms of what you can do for repeated computation, it seems as if you could use SwingUtilities invokeLater method. You are already experimenting with calling run() directly, meaning you're already thinking about using a Runnable rather than a raw Thread. Try using the invokeLater method on just the Runnable task and see if that fits your mental pattern a little better.
Here is the example from the documentation:
Runnable doHelloWorld = new Runnable() {
public void run() {
// Put your UI update computations in here.
// BTW - remember to restrict Swing calls to the AWT Event thread.
System.out.println("Hello World on " + Thread.currentThread());
}
};
SwingUtilities.invokeLater(doHelloWorld);
System.out.println("This might well be displayed before the other message.");
If you replace that println call with your computation, it might just be exactly what you need.
EDIT: following up on the comment, I hadn't noticed the Android tag in the original post. The equivalent to invokeLater in the Android work is Handler.post(Runnable). From its javadoc:
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* #param r The Runnable that will be executed.
*
* #return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
So, in the Android world, you can use the same example as above, replacing the Swingutilities.invokeLater with the appropriate post to a Handler.
No, we cannot start Thread again, doing so will throw runtimeException java.lang.IllegalThreadStateException.
>
The reason is once run() method is executed by Thread, it goes into dead state.
Let’s take an example-
Thinking of starting thread again and calling start() method on it (which internally is going to call run() method) for us is some what like asking dead man to wake up and run. As, after completing his life person goes to dead state.
public class MyClass implements Runnable{
#Override
public void run() {
System.out.println("in run() method, method completed.");
}
public static void main(String[] args) {
MyClass obj=new MyClass();
Thread thread1=new Thread(obj,"Thread-1");
thread1.start();
thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
}
}
/*OUTPUT in run() method, method completed. Exception in thread
"main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
*/
check this
The just-arrived answer covers why you shouldn't do what you're doing. Here are some options for solving your actual problem.
This particular thread is doing some
calculation in the background, if I
don't do it in the thread than it's
done in the UI thread and the user has
an unreasonably long wait.
Dump your own thread and use AsyncTask.
Or create a fresh thread when you need it.
Or set up your thread to operate off of a work queue (e.g., LinkedBlockingQueue) rather than restarting the thread.
What you should do is create a Runnable and wrap it with a new Thread each time you want to run the Runnable.
It would be really ugly to do but you can Wrap a thread with another thread to run the code for it again but only do this is you really have to.
It is as you said, a thread cannot be started more than once.
Straight from the horse's mouth: Java API Spec
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
If you need to re-run whatever is going on in your thread, you will have to create a new thread and run that.
To re-use a thread is illegal action in Java API.
However, you could wrap it into a runnable implement and re-run that instance again.
Yes we can't start already running thread.
It will throw IllegalThreadStateException at runtime - if the thread was already started.
What if you really need to Start thread:
Option 1 ) If a Thread needs to be run more than once, then one should make an new instance of the Thread and call start on it.
Can a Thread be started only once?
Yes. You can start it exactly once.
If so than what do I do if I want to run the thread again?This particular thread is doing some calculation in the background, if I don't do it in the thread than it's done in the UI thread and the user has an unreasonably long wait.
Don't run the Thread again. Instead create Runnable and post it on Handler of HandlerThread. You can submit multiple Runnable objects. If want to send data back to UI Thread, with-in your Runnable run() method, post a Message on Handler of UI Thread and process handleMessage
Refer to this post for example code:
Android: Toast in a thread
It would be really ugly to do but you can Wrap a thread with another thread to run the code for it again but only do this is you really have to.
I have had to fix a resource leak that was caused by a programmer who created a Thread but instead of start()ing it, he called the run()-method directly. So avoid it, unless you really really know what side effects it causes.
I don't know if it is good practice but when I let run() be called inside the run() method it throws no error and actually does exactly what I wanted.
I know it is not starting a thread again, but maybe this comes in handy for you.
public void run() {
LifeCycleComponent lifeCycleComponent = new LifeCycleComponent();
try {
NetworkState firstState = lifeCycleComponent.getCurrentNetworkState();
Thread.sleep(5000);
if (firstState != lifeCycleComponent.getCurrentNetworkState()) {
System.out.println("{There was a NetworkState change!}");
run();
} else {
run();
}
} catch (SocketException | InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread checkingNetworkStates = new Thread(new LifeCycleComponent());
checkingNetworkStates.start();
}
Hope this helps, even if it is just a little.
Cheers

Will Runnables block the UI thread?

I am trying to understand how UI thread's event queue works. I'm trying to run a code that can be broken into many parts but unfortunately it must run on the UI thread. So, in order to not block the UI thread and receive a ANR I was wondering if I can break that code in many Runnable objects and run them using runOnUiThread from another thread.
My question is, will this block the UI thread? If, for example, I have a piece of code that definitely runs in over 5 seconds and I break this code into, let's say 1000 Runnable objects, and add them to the event queue of the UI thread, will other events get processed by the UI thread between them?
Edit: I think I found a better way to express myself in case the above explanation is confusing.
The 1000 Runnable objects was just an example, in actual code I want to have at most 10.
Basically, I want 10 Runnable objects, each one initialising an Ad network on the UI thread. I want these Runnable objects to run one after another, not in parallel. Also, I want the UI thread to be able to process other events between running these objects, so that I don't get an ANR in case running all 10 run methods will take more than 5 seconds.
NOTE: I don't know why initialising Ad networks must be done on the UI thread, but it must, otherwise the app crashes. It also states in some of the networks' sdks' documentation that initialisation must happen on the UI thread. This is why I need to run them one after another on UI thread and I can't run them in parallel in the background.
Also, the app is actually a OpenGl game, so calls to running the Runnable objects will be made from a GL thread, not the main thread, so they will be added to the event queue, and not executed immediately.
Well, Runnable inside your runOnUiThread is just operation in Main Thread.
Imagine that some simple action like
textView.setText("example");
will block Main Thread for 5 ms. Usually you will not see it.
Now imagine that you have like 1000 same operations for 5 seconds. And every blocks Main Thread for 5 ms. Simple calculating 5ms * 1000 = 5000ms = 5 seconds. So it will block Main Thread permamently. But if you have 10 operations you will block only 50 ms, in other words its just 1% of load that you will not feel.
So possible amount of calls depends on size of View, how hard render is and how fast is device.
P.S. For adepts of AsyncTask - there is no real difference between runOnUiThread and AsyncTask because those 1000 Runnables will execute in Main Thread by the same way.
Even if I do same thing inside onCreate method of Activity that will block UI hard
Yes. Runnable executing on UI thread will block main thread.
Check if below approach is useful for you.
Create a Handler with Looper from Main :requestHandler
Create a Handler with Looper for main thread : responseHandler and override handleMessage method
post a Runnable task on requestHandler
Inside Runnable task, call sendMessage on responseHandler
This sendMessage result invocation of handleMessage in responseHandler.
Get attributes from the Message and process it, update UI
Sample code:
/* Handler */
Handler requestHandler = new Handler(Looper.getMainLooper());
final Handler responseHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
//txtView.setText((String) msg.obj);
Toast.makeText(MainActivity.this,
"Adwork task is completed:"+(String)msg.obj,
Toast.LENGTH_LONG)
.show();
}
};
for ( int i=0; i<10; i++) {
// Start Adwork task
Runnable myRunnable = new Runnable() {
#Override
public void run() {
try {
/* Your business logic goes here */
// Send some result after computation
String text = "" + (++rId);
Message msg = new Message();
msg.obj = text.toString();
responseHandler.sendMessage(msg);
System.out.println(text.toString());
} catch (Exception err) {
err.printStackTrace();
}
}
};
requestHandler.post(myRunnable);
}
Useful articles:
handlerthreads-and-why-you-should-be-using-them-in-your-android-apps
android-looper-handler-handlerthread-i
What you are looking for is an AsyncTask.
These are designed to do some background processing, while the UI thread continues. It will NOT block the UI and will NOT cause ANR.
Within the AsyncTask, is an onPostExecute method, which allows you to post results back to the UI. So it is not completely detached from the UI Thread. And an onProgressUpdate for connection during the background processing
Yes, you will feel animation will stop or start shutter if You run heavy operations in Ui thread. It's also depends of how fast device is.
What I would suggest you is to break your code in two parts. One that can be done in background and second that need Ui thread and execute them in AsyncTask.
Use doInBackgroud method to execute heavy operation and onPostExecute to update UI.
Note: If you break code into 1000 threads and run them in one moment, then probably You will hit device queue limit. (Break them into 10-50 parts. )

How do I create methods for a thread?

I'm writing an android application.
In the main thread, it is possible to define methods and then call the methods, which helps keep the code clean. In a new thread, how does one define methods, to avoid writing all the code in "one block"? Is it possible to call methods defined in the main thread, or can you define them inside the new thread somehow?
So to be clear, what I want to do is this:
volatile Runnable feedToBuffer = new Runnable()
{
#Override
public synchronized void run()
{
if(boolean)
{
MethodA();
}
else
{
MethodB();
}
}
and not this:
volatile Runnable feedToBuffer = new Runnable()
{
#Override
public synchronized void run()
{
if(boolean)
{
//Code that was in MethodA
}
else
{
//Code that was in MethodB
}
}
}
Is that possible?
I realize this info is probably out there somewhere, but haven't found it, so really grateful for any help. :)
It's perfectly possible. Thread is just a sequence of actions, and if it involves a method call, it will be executed within that sequence. It doesn't matter.
Threads are in no way tied to the structure of your code. The main difference between the threads you start and the one you have already when the app starts is the points of entry. When Android starts the main thread, it enters your app in many points, in the activity that would be the lifecycle calls like onCreate() or button click listeners. When you create a new thread, your point of entry is the run method from where you can call anything you want.
There is also a difference in that the main thread runs an event loop. Basically, there is a queue of messages that it has to process. Each time something arrives to the queue, it processes the message, then goes back to waiting. In that sense the main thread never ends. Your thread, however, stops when it reaches the end of the run method. Of course, you can implement a similar event loop for your thread yourself.
Other than that there are no fundamental differences in how the threads operate, you can call methods from any thread freely. Of course, there are rules of multithreading like avoiding blocking the main thread, synchronization, and so on, but it's too much to cover in one answer.

Java Thread only works once [duplicate]

The following code leads to java.lang.IllegalThreadStateException: Thread already started when I called start() method second time in program.
updateUI.join();
if (!updateUI.isAlive())
updateUI.start();
This happens the second time updateUI.start() is called. I've stepped through it multiple times and the thread is called and completly runs to completion before hitting updateUI.start().
Calling updateUI.run() avoids the error but causes the thread to run in the UI thread (the calling thread, as mentioned in other posts on SO), which is not what I want.
Can a Thread be started only once? If so than what do I do if I want to run the thread again? This particular thread is doing some calculation in the background, if I don't do it in the thread than it's done in the UI thread and the user has an unreasonably long wait.
From the Java API Specification for the Thread.start method:
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
Furthermore:
Throws:
IllegalThreadStateException - if the thread was already started.
So yes, a Thread can only be started once.
If so than what do I do if I want to
run the thread again?
If a Thread needs to be run more than once, then one should make an new instance of the Thread and call start on it.
Exactly right. From the documentation:
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
In terms of what you can do for repeated computation, it seems as if you could use SwingUtilities invokeLater method. You are already experimenting with calling run() directly, meaning you're already thinking about using a Runnable rather than a raw Thread. Try using the invokeLater method on just the Runnable task and see if that fits your mental pattern a little better.
Here is the example from the documentation:
Runnable doHelloWorld = new Runnable() {
public void run() {
// Put your UI update computations in here.
// BTW - remember to restrict Swing calls to the AWT Event thread.
System.out.println("Hello World on " + Thread.currentThread());
}
};
SwingUtilities.invokeLater(doHelloWorld);
System.out.println("This might well be displayed before the other message.");
If you replace that println call with your computation, it might just be exactly what you need.
EDIT: following up on the comment, I hadn't noticed the Android tag in the original post. The equivalent to invokeLater in the Android work is Handler.post(Runnable). From its javadoc:
/**
* Causes the Runnable r to be added to the message queue.
* The runnable will be run on the thread to which this handler is
* attached.
*
* #param r The Runnable that will be executed.
*
* #return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
So, in the Android world, you can use the same example as above, replacing the Swingutilities.invokeLater with the appropriate post to a Handler.
No, we cannot start Thread again, doing so will throw runtimeException java.lang.IllegalThreadStateException.
>
The reason is once run() method is executed by Thread, it goes into dead state.
Let’s take an example-
Thinking of starting thread again and calling start() method on it (which internally is going to call run() method) for us is some what like asking dead man to wake up and run. As, after completing his life person goes to dead state.
public class MyClass implements Runnable{
#Override
public void run() {
System.out.println("in run() method, method completed.");
}
public static void main(String[] args) {
MyClass obj=new MyClass();
Thread thread1=new Thread(obj,"Thread-1");
thread1.start();
thread1.start(); //will throw java.lang.IllegalThreadStateException at runtime
}
}
/*OUTPUT in run() method, method completed. Exception in thread
"main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
*/
check this
The just-arrived answer covers why you shouldn't do what you're doing. Here are some options for solving your actual problem.
This particular thread is doing some
calculation in the background, if I
don't do it in the thread than it's
done in the UI thread and the user has
an unreasonably long wait.
Dump your own thread and use AsyncTask.
Or create a fresh thread when you need it.
Or set up your thread to operate off of a work queue (e.g., LinkedBlockingQueue) rather than restarting the thread.
What you should do is create a Runnable and wrap it with a new Thread each time you want to run the Runnable.
It would be really ugly to do but you can Wrap a thread with another thread to run the code for it again but only do this is you really have to.
It is as you said, a thread cannot be started more than once.
Straight from the horse's mouth: Java API Spec
It is never legal to start a thread
more than once. In particular, a
thread may not be restarted once it
has completed execution.
If you need to re-run whatever is going on in your thread, you will have to create a new thread and run that.
To re-use a thread is illegal action in Java API.
However, you could wrap it into a runnable implement and re-run that instance again.
Yes we can't start already running thread.
It will throw IllegalThreadStateException at runtime - if the thread was already started.
What if you really need to Start thread:
Option 1 ) If a Thread needs to be run more than once, then one should make an new instance of the Thread and call start on it.
Can a Thread be started only once?
Yes. You can start it exactly once.
If so than what do I do if I want to run the thread again?This particular thread is doing some calculation in the background, if I don't do it in the thread than it's done in the UI thread and the user has an unreasonably long wait.
Don't run the Thread again. Instead create Runnable and post it on Handler of HandlerThread. You can submit multiple Runnable objects. If want to send data back to UI Thread, with-in your Runnable run() method, post a Message on Handler of UI Thread and process handleMessage
Refer to this post for example code:
Android: Toast in a thread
It would be really ugly to do but you can Wrap a thread with another thread to run the code for it again but only do this is you really have to.
I have had to fix a resource leak that was caused by a programmer who created a Thread but instead of start()ing it, he called the run()-method directly. So avoid it, unless you really really know what side effects it causes.
I don't know if it is good practice but when I let run() be called inside the run() method it throws no error and actually does exactly what I wanted.
I know it is not starting a thread again, but maybe this comes in handy for you.
public void run() {
LifeCycleComponent lifeCycleComponent = new LifeCycleComponent();
try {
NetworkState firstState = lifeCycleComponent.getCurrentNetworkState();
Thread.sleep(5000);
if (firstState != lifeCycleComponent.getCurrentNetworkState()) {
System.out.println("{There was a NetworkState change!}");
run();
} else {
run();
}
} catch (SocketException | InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Thread checkingNetworkStates = new Thread(new LifeCycleComponent());
checkingNetworkStates.start();
}
Hope this helps, even if it is just a little.
Cheers

Updating the GUI from a TimerTask using Handler

Globally, I have a the following:
Timer timer = new Timer();
in my onResume() I have the following code.
timer.schedule(new syncTimerTask(), 1, 30000);
and my syncTimerTask is as follows :
class syncOutgoingUpdatesTimerTask extends TimerTask
{
public void run()
{
//some sync process with outer back end server
//fetch results etc
myHandler.post(myRunnable);
}
}
my handler and runnable are declared globally as follows
final Handler myHandler = new Handler();
final Runnable myRunnable = new Runnable()
{
public void run()
{
//update GUI, text views whatever.
}
};
And inside my onPause() I call timer.cancel();
The above code is neat, straight to the point and does the job perfectly.
But in order to grasp the idea better, I have some concerns and questions.
Assume the syncing too a lot of time, and the user pressed the back button. This will cause the onPause to get caused , which will stop the timer from repeating itself, however the running TimerTask will continue running. But what happens when the code reaches the line of myHandler.post(myRunnable); where the handler calls the runnable, but there is no GUI to update ? Do I get a null pointer there ?
Assume the sync started and again it took a lot of time, in which state, the user pressed the home button and got out of the app and removed the app from the 'recent apps' which 'kills' the app, calling onDestroy() on all methods. In this case, does the thread of the timer (which is a seperate thread and not the UI thread, stops wherever it is, (even though it might be in the middle) because it is associated with the app ?), assume this is true, the code won't even reach the myHandler.post(myRunnable); so no null pointers will occur.. is this the case ?
Yes, the event will run, and if you nullify things out it might cause problems. The best you can do is to have a flag that tells you, from your Runnable, that the activity is paused.
No, the app is not killed, just stopped (unless the Android process manager kills it for memory as usual). In this case your timer thread continues running and executes the Runnable in the main thread, with the same potential problems of 1.

Categories