Setting up the correct multi threading - java

Unfortunately I have a pretty bad understanding of how to properly set up threading. I know there is a bunch of info on this both here on SO.SE and on other sites but I can't seem to relate what I read correctly to what I'm doing.
My problem is that I have a method that takes two parameters where one is divided by the other. The quotient (result) is used to fill up a visual progress bar. When the quotient gets to 1, (readBytes/contentLength == 1), I want some thread (I guess) to wait for a given time before the progress bar is removed from the layout. I know all the code needed to set the value to the progress bar and how to remove it from the view, my question is how do I make it wait for, say, 2000 ms before the action is triggered to remove the component?
This is probably basic threading knowledge but I'm having huge problems with it.
So far I've tried these two approaches:
#Override
public void updateProgress(long readBytes, long contentLength) {
this.contentLength = contentLength;
if(readBytes != 0 && contentLength != 0 && fileListItem != null) {
fileListItem.getProgressIndicator().setValue(readBytes/contentLength);
synchronized (this) {
while(readBytes/contentLength != 1) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
fileListItem.removeProgressIndicator();
}
}
}
if(!itemIsAdded) {
checkFileCompatibility(contentLength);
}
}
AND
#Override
public void updateProgress(long readBytes, long contentLength) {
this.contentLength = contentLength;
if(readBytes != 0 && contentLength != 0 && fileListItem != null) {
if(readBytes/contentLength == 1) {
Thread t = new Thread();
t.start();
try {
t.wait(2000);
fileListItem.removeProgressIndicator();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t.interrupt();
} else {
fileListItem.getProgressIndicator().setValue(readBytes/contentLength);
}
}
if(!itemIsAdded) {
checkFileCompatibility(contentLength);
}
}
With no success. In the first example the main thread seems to be the one waiting and nothing happens. And in the second example I get an exception on the t.wait(2000);. I'm at a loss of how I should do..
EDIT: With the input from Bohemian I got it working.
#Override
public void updateProgress(final long readBytes, final long contentLength) {
this.contentLength = contentLength;
if(readBytes != 0 && contentLength != 0 && fileListItem != null) {
if(!threadIsRunning) {
new Thread(new Runnable() {
#Override
public void run() {
threadIsRunning = true;
while(!fileIsAdded) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
LOGGER.error(e.getMessage());
break;
}
}
fileListItem.removeProgressIndicator();
threadIsRunning = false;
}
}).start();
}
fileListItem.getProgressIndicator().setValue(readBytes/contentLength);
if(readBytes == contentLength)
fileIsAdded = true;
}
if(!itemIsAdded) {
checkFileCompatibility(contentLength);
}
}
It still needs some tidying up but the basics are now working!

In all probability SwingWorker is the right tool for your task. There is a full code sample in the Javadoc. Notice the method setProgress -- that's ideal to update your progress bar.
If all you need is really just a fixed 2 second delay for clearing the progress bar, then you want to use a Swing Timer. It doesn't even involve multithreading, you just write a callback handler that will be executed after the specified delay.

I wouldn't have the main thread wait. It's bad practice because it isn't scalable and makes your GUI jittery.
Instead, I would pass a timeout value and a couple of callbacks to the worker thread to execute when it exceeds its timeout/completes its work. That way the main thread is free to go back to doing whatever it wants to.
Just for illustration purposes, your "completion" callback might look like:
new Runnable() {
public void run() {
// code that hides the progress bar
}
}
Your "timeout" callback might look like:
new Runnable() {
public void run() {
// code that displays an error message
}
}
By the way, to get a thread to do something, you also pass it a Runnable:
new Thread(new Runnable() {
public void run() {
// code that runs when your thread starts
}
}).start();

I think what you really need is
Thread.sleep(2000);
instead of wait. While wait can be used for sleeping, its primary function is for inter-thread signaling and requires a lock on the object being waited on, which you have not acquired, hence the exception.
Edit: Upon further inspection I notice that you are not doing things correctly. You are just creating a thread with no associated run method:
Thread t = new Thread();
t.start();
Hence your thread is not executing anything.
I suggest reading a Java threading tutorial on how to set up threads correctly: http://docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html

Related

Android - Creating a Sync Timer

I know timers work by making the thread sleep for x amount of time but I was wondering if there is some sort of timer out there that doesn't run on a thread that's not the UI thread. I thought about using a loop that constantly compares the system time in milliseconds, but I want to use that as a last resort as it does not seem very efficient.
EDIT:
Stacktrace:
07-25 14:38:38.037 22108-22124/com.example.myapp E/ViewRootImpl﹕ com.example.myapp.Main : Only the original thread that created a view hierarchy can touch its views.
java.lang.RuntimeException
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6355)
at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:929)
at android.view.ViewGroup.invalidateChildFast(ViewGroup.java:4466)
at android.view.View.invalidateViewProperty(View.java:11112)
at android.view.View.setTranslationY(View.java:10472)
at android.view.View.setY(View.java:10400)
at com.example.myapp.Player.update(Player.java:29)
at com.example.myapp.Main.update(Main.java:70)
at com.example.myapp.Main.access$000(Main.java:15)
at com.example.myapp.Main$1.run(Main.java:33)
at java.util.Timer$TimerImpl.run(Timer.java:284)
Relative Code:
if (!onGround){
playerVisual.setY(playerVisual.getY() + this.gravity);
}
if (playerVisual.getY() >= this.main.getDevice().getHeight() - 10){
this.onGround = true;
}
else {
this.onGround = false;
}
playerVisual is an ImageView if you were wondering.
This is a solution based on AsyncTask:
class AsyncTimer extends AsyncTask<Void, Void, Void>
{
boolean alive = true;
long startMS;
long intervalMS;
MainActivity activity;
public AsyncTimer(long startMS, long intervalMS, MainActivity activity)
{
this.startMS = startMS;
this.intervalMS = intervalMS;
this.activity = activity;
}
protected Void doInBackground(Void... params)
{
try
{
Thread.sleep(startMS);
}
catch (Exception e)
{
Log.e("Error", e.getMessage());
e.printStackTrace();
}
while (alive)
{
try
{
alive = activity.updateUI();
Thread.sleep(intervalMS);
}
catch (Exception e)
{
Log.e("Error", e.getMessage());
e.printStackTrace();
}
}
return null;
}
}
Using it in MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
...
new AsyncTimer(0, 1000, this).execute();
}
public boolean updateUI()
{
Log.d("Timer", "tick");
...
return true;
}
This is a solution for updating the GUI from a scheduled task. Use Handler instead of Timer
final Handler handler = new Handler();
final Runnable myRunnable = new Runnable()
{
public void run()
{
handler.postDelayed(myRunnable, 1000); //1 second
/*UPDATE GUI*/
update();
}
};
myRunnable.run();
You bascially want to block the current thread / wait on a condition - well
there are several options - the easiest one is to use Semaphore :
final Semaphore semaphore = new Semaphore(0); //not available at first
try
{
semaphore.tryAcquire(1, TimeUnit.SECONDS); //block for 1 second since it isnt available
}
catch(InterruptedException ex)
{
//do something sensible here
}
Another option is CountDownLatch :
final CountDownLatch latch = new CountDownLatch(1); //1 latch available
try
{
latch.await(1, TimeUnit.SECONDS) //since currently one latch is available this will timeout
}
catch(InterruptedException ex)
{
//do something sensible here
}
Granted : thats somewhat of an abuse of these classes, but it works flawlessy.
You could even use Object.wait but since an object can receive "spurious wakeups" you would have to deal with those - which isnt always as easy as it may appear to be at first.
Basically, you can use pretty much any mechanism which allows you to reliably "wait" on something - until your next time-slice is ready to be taken (hence : timeout on something) and continue in your loop.
In languages other than Java its possible to (reliably) suspend / pause the current thread for a fixed amount of time - thats even better but it breaks quite a few programming paradigms and it can be hard to understand; its best to not touch the thread itself unless you're really experienced and have a lot of knowledge about these things, blocking method invocations are almost always the best choice, even if that means writing a few extra lines of code.

How to interrupt a thread with infinite loop and sleep in Java

i've been fighting with this over few hours now. Here's the code:
#Override
public void run()
{
try
{
wscript.setBid(0.30);
wscript.setServiceMode(WebScript.ServiceMode.ON);
for(;!Thread.currentThread().isInterrupted();)
{
Positioning(demandedPosition, maximumBid);
if(Thread.currentThread().isInterrupted())
break;
Thread.sleep(10000);
}
wscript.setServiceMode(ServiceMode.OFF);
Log("Algorithm has been canceled!");
}
catch (InterruptedException e)
{
wscript.setServiceMode(ServiceMode.OFF);
Log("Algorithm has been canceled!");
return;
}
The thing is, that i would like to interrupt it in legit way with this code:
private void StopService()
{
service.interrupt();
}
When I call this method when Thread.sleep() is running, it gets InterruptedException and everything works fine. However, as I call it when the PositioningAlgorithm is running nothing is happenning, the thread acts like it never got the interruption state.
Regards,
DualCore
EDIT: It is essential for me that the call Log("Algorithm has been canceled!"); will be executed after interruption.
SOLVED: I had overwritten Thread.interrupt() to edit class local variable which was checked whether the thread is ready to end:
service = new Thread(mechanism)
{
#Override
public void interrupt()
{
super.interrupt();
mechanism.ReadyToReturn = true;
}
};
And here's updated thread main algorithm:
#Override
public void run()
{
try
{
wscript.setBid(0.30);
wscript.setServiceMode(WebScript.ServiceMode.ON);
for(;!ReadyToReturn || !Thread.currentThread().isInterrupted();)
{
Positioning(demandedPosition, maximumBid);
if(ReadyToReturn || Thread.currentThread().isInterrupted())
break;
Thread.sleep(10000);
}
wscript.setServiceMode(ServiceMode.OFF);
Log("Algorithm has been canceled!");
}
catch (InterruptedException e)
{
wscript.setServiceMode(ServiceMode.OFF);
Log("Algorithm has been canceled!");
return;
}
}
The reason why this might be happening is that Positioning clears isInterrupted flag (see https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#interrupted%28%29) and/or catches somewhere InterruptedException (or Exception/Throwable).
One possibility is to use another flag (e.g. using volatile variable/ AtomicBoolean/ThreadLocal) to indicate whether the thread should be interrupted.

How to wait in loop in Vaadin?

Im trying to display series of photos on one page with time interval. In countinuos while loop i got:
while(true){
if (zmienna == fa.length) zmienna = 0;
Image obrazek = new Image("",pliki[zmienna]);
layout.replaceComponent(staryObrazek, obrazek);
obrazek.requestRepaint();
staryObrazek = obrazek;
zmienna++;
try {
Thread.sleep(2000) ;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
It showing only waiting icon, dispaying mwthod works fine without loop. Do anyone has an idea how I should fic this issue?
In all modern UI systems you will have to not suspend the main thread, but use a background thread to update the UI. Otherwise you block the whole UI.
In Vaadin 7 you can enable server push and then use a background thread to change the image every 2 seconds.
Enabling push is described in the book of vaadin https://vaadin.com/de/book/vaadin7/-/page/advanced.push.html
Your code could look like this:
public class PushyUI extends UI {
#Override
protected void init(VaadinRequest request) {
// Set first component/image
setContent(chart);
// Start the update thread
new ImgUpdThread().start();
}
class ImgUpdThread extends Thread {
#Override
public void run()
{
// Update the data for a while
while (count < 100) {
Thread.sleep(1000);
access(new Runnable() {
#Override
public void run() {
//update the UI as in your code above
}
});
}
}
It is important to use the access(...) method to sync access to the UI elements.

Java code speed improvement

Hi all may such a code cause lag of process?
while(true)
if(!connected) break;
As we see it checks for condition all the time. Would it be faster if I set small sleep in each iteration.
The code runs on Android GingerBread.
EDIT:
It waits for other Thread to finish and set variable Connected to false. Variable connected is used like lock. thread usually finds it true and waits to be false. then sets to true and only changes it at the end.
I think it would be better to add small sleep in your loop, to free processor resources for other processes, especially on one-core processor.
I belive it could be like this:
while(connected) {
// do stuff...
Try something like this:
private Integer connected;
private ConnectedListener connectedListener;
public interface ConnectedListener {
public void onDisconnected();
}
private void startThreads() {
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
#Override
public void run() {
synchronized (connected) {
connected++;
}
// do some random long work
synchronized (connected) {
connected--;
if (connected == 0 && connectedListener != null) {
//let the listener know that we are completely disconnected
connectedListener.onDisconnected();
}
}
}
}).start();
}
}

IllegalArgumentException in unlockCanvasAndPost (android live wallpaper)

I've created my first live wallpaper implementing drawing in a separate thread. So now I have a WallpaperService and my WallpaperPainter who does the job. The problem is that I getting a IllegalArgumentException in unlockCanvasAndPost method on some of devices (Samsung Note is the one). I've read all recomendations I could find but couldn't fix that bug. Seems like the unlockCanvasAndPost is called when surface is destroyed so canvas is invalid. Here is the essential parts of code:
In wallpaper service:
#Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
super.onSurfaceChanged(holder, format, width, height);
painting.setSurfaceSize(width, height);
}
#Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
painting.start();
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
boolean retry = true;
painting.stopPainting();
while (retry) {
try {
painting.join();
retry = false;
} catch (InterruptedException e) { }
}
super.onSurfaceDestroyed(holder);
}
In the painting thread:
public void stopPainting() {
this.run = false;
synchronized(this) {
this.notify();
}
}
public void run() {
this.run = true;
Canvas c = null;
while (run) {
try {
synchronized (this) {
Thread.sleep(50);
c = this.surfaceHolder.lockCanvas();
doDraw(c);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (c != null) {
this.surfaceHolder.unlockCanvasAndPost(c); // << -- HERE IS THE PROBLEM
}
}
// if pause...
synchronized (this) {
if (wait) {
try {
wait();
} catch (Exception e) { }
}
}
}
}
Can anyone give me any clue what I'm doing wrong? I'm new both for Java and Android.
If error is: UnlockAndPost Failed, it means it unlocked no buffer.
After this.surfaceHolder.unlockCanvasAndPost(c);
you can append
this.surfaceHolder.lockCanvas();
(sorry for my poor English proficiency)
When you open the preview of wallpaper, creates the object WallpaperService and further creates an instance of Engine. Then the stream starts drawing wallpaper.
Then, when you click "Set wallpaper" - a new instance of WallpaperService is not created. But he call the onCreateEngine() method, which returns another (second) instance of Engine. Which also runs its own thread.
Now you have two competing thread!!! So they lead to an exception being thrown.
All you need to do to fix the bug - is to write a correct method onCreateEngine().
replace this:
#Override
public Engine onCreateEngine() {
return new SampleEngine();
}
to this:
private SampleEngine engine;
#Override
public Engine onCreateEngine() {
if (engine!=null) {
engine.painting.stopPainting();
engine = null;
}
engine = new SampleEngine();
return engine;
}
I don't see a definitive problem but here are some thoughts.
There is a chance that you unlock a canvas that has not been locked. I would set c = null; at the top of your while loop otherwise the previous value of c would be unlocked the next time through the loop.
while (run) {
Canvas c = null;
...
Your run field should be marked as volatile because it is accessed by multiple threads.
Never call Thread.sleep(...) inside of a synchronized block. That's a very bad practice since it blocks other threads unnecessarily.
Make sure you at least log your exceptions. Be extremely careful about catch (Exception e) {}. All that does is mask your problems.
There isn't much point in doing the join() inside a while loop. If your thread gets interrupted you should interrupt the painting thread and quit.
Since you are both sleeping and waiting, it would make more sense to remove the sleep and do something like:
try {
synchronized (this) {
if (wait) {
wait();
else {
wait(50);
}
}
} catch (Exception e) {
e.printStackTrace();
}
I had the same problem with my live wallpaper. On a Nexus 5 emulator it runs fine, but when I run it on a Nexus 10 emulator it crashes the moment the app loads.
I found out that the problem was because the default Skin for the emulator has the wrong resolution. After I changed the Skin to "No Skin" then I don't get the crash anymore.
For more information on how to fix the Skin with wrong resolution, please see:
Android Studio - Tablet emulator not showing correct resolution

Categories