Using Synchronized in While Loops - android

I've found the following code does not work because the while loop steals the lock indefinitely:
public void run()
{
while(true)
{
synchronized(run)
{
if (!run) break;
[code]
}
}
}
public void stopRunning()
{
synchronized(run)
{
run = false;
}
}
My goal is to ensure that I don't return from a stopRunning() command until I know that my run() function is no longer actually running. I'm trying to prevent the run function from continuing to reference other things that I'm in the process of destroying. My first thought then is to add a line of code such as Thread.sleep(100) prior to synchronized(run) in order to ensure that it releases the lock. Is this the recommended practice or am I overlooking something [stupid/obvious]?
Thanks!

If you just need stopRunning() to block until run() finishes doing stuff, you could just use a CountDownLatch set to 1. Call it stoppedSignal or something, and in run() you can call stoppedSignal.countDown() when it is finished. In stopRunning you can then set your condition for run() to finish and then call stoppedSignal.await(). It won't proceed until run() "releases" the latch by counting down. This is just one way to do it that would be a bit neater. All the synchronized block stuff that be got rid of.
Beware of the "synchronized" keyword - it's a very blunt and old tool. There are some wonderful things in the concurrency package that fulfil specific purposes much more neatly. "Concurrency In Practice" is a fantastic book on it.

Would something like this suffice?
public void run()
{
while(run)
{
[code]
}
onRunStopped();
}
public void stopRunning()
{
run = false;
}
public void onRunStopped()
{
// Cleanup
}

while synchronized(run) will lock run, you can use run.wait() to freeze the thread run() is executed in.
in another thread, use run.notify() or run.notifyAll() to get run() to continue.
synchronized is used to sync between threads. use it only if there is a potential race condition between 2 or more of them.

Ensure the 'run' object is the same from both point in the code.
The while loop should be synchronizing to the same object as the stopRunning() method.
The while loop is not hogging the lock, it is more likely that the two pieces of code could be referencing a different object. But I cannot tell because the run object is not shown in the code.

There are probably more elegant solutions, but I believe you could solve it with the changes bellow:
private boolean lock;
public void run()
{
while(true)
{
synchronized(lock)
{
if (!run) break;
[code]
}
}
}
public void stopRunning()
{
run = false;
synchronized(lock){ }
}

Related

How to correctly use a Workerthread?

I've been writing android apps for some months now, and I'm at the point where I'm building an actual needed app.
As I want that to work nice and fast, I made a Workerthread to do all kinds of tasks in the background while the UI can...build up and work and stuff.
It's based on the Android Studio Drawer app blueprint.
In Main.onCreate I got my operator=new Operator(), which extends Thread.
Now, when loading a new Fragment, it sometimes calls MainActivity.operator.someMethod() (I made operator static so I can use it from anywhere), and after some time I realized, the only tasks actually running in background are those in the operators run() method and an Asynctask my login Fragment runs. Everything else the UI waits for to complete and therefore gets executed by the UI thread.
So I thought: no problem! My operator gets a handler which is built in run(), and I change those tasks:
public void run() {
Looper.prepare(); //Android crashed and said I had to call this
OpHandler = new Handler();
LoadLoginData();
[...Load up some Arrays with hardcoded stuff and compute for later use...]
}
public void LoadLoginData() {
OpHandler.post(LoadLoginDataRunnable);
}
private Runnable LoadLoginDataRunnable = new Runnable() {
#Override
public void run() {
if(sharedPreferences==null)
sharedPreferences= PreferenceManager.getDefaultSharedPreferences(context);
sessionID=sharedPreferences.getString("sessionID", null);
if(sessionID!=null) {
postenID = sharedPreferences.getString("postenID", PID_STANDARD);
postenName = sharedPreferences.getString("postenName", PID_STANDARD);
context.QuickToast(sessionID, postenName, postenID);
}
}
};
context is my MainActivity, I gave the operator a reference so I could send Toasts for Debugging.
But now, the Runnables seem to not run or complete, any Log.e or Log.d stuff doesn't arrive in the console.
After some googeling and stackoverflowing, everyone is just always explaining what the difference is between Handlers, Asynctask, and Threads. And the multitask examples always only show something like new Thread(new Runnable{run(task1)}).start times 3 with different tasks.
And so became my big question:
How to correctly, over a longer time (~lifecycle of the MainActivity), with different tasks, use a background thread?
Edit: to clarify, I would also like a direct solution to my special problem.
Edit 2: after reading nikis comment (thank you), the simple answer seems to be "use HandlerThread instead of thread". Will try that as soon as I get home.
Trying a HandlerThread now. It seems my OpHandler, initialized in run(), gets destroyed or something after run() has finished, not sure whats up here (this is btw another mystery of the kind I hoped would get answered here). I get a NullpointerException as soon as I try to use it after run() has finished.
Make your worker thread own a queue of tasks. In the run() method, just pop a task from the queue and execute it. If the queue is empty, wait for it to fill.
class Operator extends Thread
{
private Deque<Runnable> tasks;
private boolean hasToStop=false;
void run()
{
boolean stop=false;
while(!stop)
{
sychronized(this)
{
stop=hasToStop;
}
Runnable task=null;
synchronized(tasks)
{
if(!tasks.isEmpty())
task=tasks.poll();
}
if(task!=null)
task.run();
}
}
void addTask(Runnable task)
{
synchronized(tasks)
{
tasks.add(task);
}
}
public synchronized void stop()
{
hasToStop=true;
}
}

How to stop the thread on Android?

I have a function parseData which recieves Vector of urls and gives them to DataParser. DataParser gets data from urls and parses it. The problem is that user might request new urls to parse before previous parsingis finished. In that case previous data becomes irrelivant but thread continues to work. Since there might be a lot of urls in one request and parsing each of them takes time, after 5-6 sequential requests phone starts work very slowly.
Here is the code snippet.
public void parseData(final String key, final Vector<String> data)
{
this.key = key;
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
DataParser dp = new DataParser(key);
dp.setData(data);
dp.startParse();
}
});
thread.start();
}
I think the solution might be to keep extra flag in DataParser. Since it requesting urls in cycle, I can check flag and break cycle, but it seems to me rude.
Are there other ways to solve this issue?
You can use interrupt() method:
thread.interrupt();
BTW, checking some kinds of flags isn't so rude and bad style. But don't forget to declare such flag as volatile.
You need to check periodically for a flag in worker thread. Set that flag if worker thread is to be stopped.
This kind of thing is done well in an Async Task instead of straight thread. There is a cancel method to them and an is canceled function that can tell you to stop.
You could constantly check on a boolean flag every time you perform a parsing operation, and stop parsing if this flag becomes true.
From another thread, you can establish the value of this flag to "cancel" the parsing.
This is the technique AsyncTasks use to cancel the work done in doInBackground().
class DataParser {
private boolean volatile mIsCancelled = false;
public void startParsingAsync() {
new Thread(new Runnable(
public void run() {
parse();
}
)).start();
}
private void parse() {
while(!isCancelled()) {
parseNextNode();
}
}
private synchronized void isCancelled() {
return mIsCancelled();
}
public synchronized void cancel() {
mIsCancelled = true;
}
private void parseNextNode() {
.....
}
From another thread, you can invoke the method cancel() once the data has become irrelevant.
Note the you have to synchronize the access to the flag, as it will be accessed from different threads.
This code is not tested, so it may not even compile...
That's the theory, but for practical uses, you should use an AsyncTask, which gives the cancelling for you.

Android - Proper way to listen for variable change, and do something upon change?

The app I'm making requires that a bit of code be executed whenever the value of a particular variable changes from 0 to 1.
The handler example below is the method I'm currently using to do this (I copied it from someone else).
I have a feeling it's not a proper method though because having just three of these handlers in my app causes the UI to be fairly unresponsive, and causes the device (a phone) to become quite hot.
As you can see, I've put 10ms delays in the handlers to try to deal with this.
Isn't there something more like OnClickListener that can listen at all times for a variable value change without putting such stress on the CPU?
I'm pretty new to Java and Android so a simple example would be very much appreciated.
final Handler myHandler1 = new Handler();
new Thread(new Runnable()
{
#Override
public void run()
{
while (true)
{
try
{
Thread.sleep(10);
myHandler1.post(new Runnable()
{
#Override
public void run()
{
if (myVariable == 1)
{
myVariable = 0;
//do stuff
}
}
});
} catch (Exception e) {}
}
}
}).start();
You must set your variable via a setter method. Then, you can be reactive to that change.
public void setMyVariable(int value) {
this.myVariable = value;
if (myVariable == 1) {
doSomethingWhen1();
} else if (myVariable == 0) {
doSomethingWhen0();
}
}
A more elegant way to do that will be an observer pattern, Here you can find more detailed documentation about it.
You must certainly avoid while(true) loops on mobile device, it will drain your battery and you are also blocking the UI thread. That's the reason why your UI is unresponsive and your cellphone it's quite hot.

Threading on Android

I have the following void:
public void load() {
//loading big picture from the Internet
}
And i want it to run in a new Thread.
I can call this procedure like this:
new Thread(new Runnable() {
public void run() {
load();
}
}).start();
or it would be better to modify this void:
public void load() {
new Thread(new Runnable() {
public void run() {
//loading big picture from the Internet
}
}).start();
}
and simply call it:
load();
Or there is no different?
Functionally, they are identical. There are designed details that might make you consider the first way over the other.
You may want the first option if you had a lot of different threads that didn't their own individual things but also called load(). In that case, you already had created the thread, so if they called load() you wouldn't want/need to create another.
The second option is very convenient. You can simply call load() wherever you want. If, in the future, the load() method changes to a point where it's not blocking, then you can change it and no further code changes would be needed.
Alternatively, consider using AsyncTask for this as previously suggested. It was specifically built for exactly what you're trying to do.

HandlerThread should i override run()?

I'm trying to use the HandlerThread class to manage thread in my application. The following code is working great :
public class ThreadA extends HandlerThread
{
private void foo()
{
//do something
}
private void bar()
{
//Do something else
}
#Override
public boolean handleMessage(Message msg) {
switch(msg.what)
{
case 1:
{
this.foo();
break;
}
case 2:
{
this.bar();
break;
}
}
return false;
}
#Override
protected void onLooperPrepared()
{
super.onLooperPrepared();
synchronized (this) {
this.AHandler = new Handler(getLooper(),this);
notifyAll();
}
}
}
1- Should i override the run() method ? In a "classic" thread most of the code is located in the run method.
2- Lets imagine i need my foo() method to be a infinite process (getting a video streaming for example).
What's the best solution ?
Overriding run with my foo() code ?
Simply adding a sleep(xxx) in foo() :
private void foo()
{
//do something
sleep(100);
foo();
}
-Using a delayed message like :
private void foo()
{
//do something
handler.sendEmptyMessageDelayed(1,100);
}
PS : Asynctask will not cover my need , so do not bother to tell me to use it.
Thanks
I think you didn't get the idea of HandlerThread. HandlerThread is designed to implement thread that handles messages. What this means is that it uses Looper.loop() in its run() method (and that's why you shouldn't override it). This in turn means that you don't need to sleep in onHandleMessage() in order to prevent thread from exiting, as Looper.loop() already takes care of this.
To summarize:
No, do not override run().
You don't need to do anything to keep thread alive.
If you want to learn/undestand more about HandlerThread, read about Looper and Handler classes.
You shouldn't override the run method in the HandlerThread since that is where the core functionality of the class actually occurs. Based on what you are showing, I also see no reason to do so.
If your task itself is infinite, there isn't anything preventing you from having it execute that way. The only reason you might want to use handler.sendEmptyMessageDelayed is if you plan to have other tasks that you want run queued on the HandlerThread while foo() is executing. The other approach you recommended will prevent the HandlerThread from handling any other message. That being said, I suspect there is a better way to make your task infinite.
Finally, you should remember to stop your infinite task and call HandlerThread.getLooper().quit() to make sure your HandlerThread stops nicely.

Categories

Resources