After reading Java doc plus stackoverflow's answers no this question, i came to a thought that Thread.sleep() sleeps the current thread. Okay. How do i determine what is the current thread in my case?
When this code runs for the first time, it runs in a default thread which executes the main function. Am i right? So we sleep this thread for a second to allow the others threads to do their stuff.
After the invokeLater() is called, we start running the render method from the brand new thread so when we call Thread.sleep() the second time, we interrup this new thread while the default one is running without any kind of interruption. Am i missing something here?
The last thing i don't understand is that when i test this code, by calling Thread.sleep() it interrupts the whole Swing thing: GUI, events etc. That means that everything that is not Swing related in my program should run absolutely seamlessly but seems like it's not.
private void render() {
if (bs == null) {
createBufferStrategy(3);
bs = getBufferStrategy();
}
g = bs.getDrawGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
onRender(g);
g.dispose();
bs.show();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
EventQueue.invokeLater(() -> render());
}
Thread.sleep() sleeps the current thread [but] How do i determine what is the current thread?
You misunderstand what "current thread" means. It means the thread that called the method.
Don't think of Thread.sleep(n) as doing anything to a thread. Think of it as a method that does nothing, and then returns n milliseconds later.
When i pass a runnable into invokeLater, i'm creating another thread and use its method run to call that render method. How is that possible?
invokeLater(r) puts r onto a queue. It also creates the EDT, but only if the EDT does not already exist. So, there will never be more than one EDT. The EDT eventually will pick r off the queue and call r.run().
In your case, r is created by the lambda expression, () -> render(). Every time your render() function is run, it will queue up a new Runnable(), and the EDT will almost immediately call render() again.
When i test this code, by calling Thread.sleep() it interrupts the whole Swing thing
ALL events are handled by the EDT. When the EDT calls your render() method, it can't do anything else---it can't handle any events---until render() returns. The sleep(1000) call insures that render() will not return for at least one full second. That is one full second during which your program will be unable to respond to any user input.
Since the EDT will be calling your render() function more or less continuously, that means that the EDT will spend almost all of its time sleeping, your program will be mostly unresponsive to user input.
A static invocation of Thread.sleep...
Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.
(bold statement underlined by me).
If you invoke it in a thread that seems to render some UI (or in general, in the main running thread), you will almost certainly see some degradation in usability.
Note that the concepts of a thread sleeping and interrupting a thread are different.
That's why you need to catch InterruptedException when invoking Thread.sleep, as the thread might be interrupted while sleeping, e.g. by another thread invoking interrupt on the sleeping thread.
Also note that a thread can interrupt itself as well, but that obviously would not happen while it's sleeping at the same time.
Also note in your case that render adds an ansynchronous invocation of itself through a new Runnable to the EventQueue recursively, which seems pretty dangerous.
The last thing i don't understand is that when i test this code, by calling Thread.sleep() it interrupts the whole Swing thing: GUI, events etc. That means that everything that is not Swing related in my program should run absolutely seamlessly but seems like it's not.
All UI events in Swing run in a single thread. Usually it is a main thread. If this thread are taken for some activity then whole UI will hang for some time. To avoid hanging do not make heavy calculation in listeners of UI controls.
Only the Swing main thread or event dispatch thread will execute the render method.
If you want that worker threads execute code you must tell them explicitly from the main thread.
SwingWorker worker = new SwingWorker<ImageIcon[], Void>() {
#Override
public ImageIcon[] doInBackground() {
final ImageIcon[] innerImgs = new ImageIcon[nimgs];
for (int i = 0; i < nimgs; i++) {
innerImgs[i] = loadImage(i+1);
}
return innerImgs;
}
#Override
public void done() {
//Remove the "Loading images" label.
animator.removeAll();
loopslot = -1;
try {
imgs = get();
} catch (InterruptedException ignore) {}
catch (java.util.concurrent.ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
};
For example you could span several SwingWorker and after that sleep the main thread.
Related
I'm new to multithreading, so excuse my potentially silly question.
I need to use several threads in my app. However, virtually all of these threads will modify the UI. I've successfully used runOnUiThread, but what I fear is that if I create different threads of the same type, they will all be running on one thread, the "Ui thread", which may slow down my app.
Is this true, or am I greatly misunderstanding?
My thread which I will essentially multiply:
private void goldPerSecondMethod() {
new Thread() {
public void run() {
while (goldCount < 1000) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
goldCount += 0.1f;
textGoldCount.setText(goldCount + " Gold");
textGoldCount.setGravity(Gravity.CENTER);
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
All help is appreciated!
I need to use several threads in my app.
Why? For example, there is no need for a thread that you create yourself in the code sample you have above. Use a postDelayed() loop (no threads), or use ScheduledExecutorService (threads, but you don't have to create them) for timing.
what I fear is that if I create different threads of the same type, they will all be running on one thread, the "Ui thread", which may slow down my app.
I have no idea what "the same type" means. In your code snippet above, everything in the Runnable that you pass to runOnUiThread() will be executed on the main application thread (sometimes called the UI thread). Everything else in your outermost run() will be executed on this background thread.
It is correct that you need to run UI updates on the UI thread. Hence you do textGoldCount.setText(...) on the UI thread. Technically, this is a correct approach.
However, it's unnecessary to call setGravity(...) every time you update the text field. You should be able to set the gravity once. Best place would be probably your XML view description.
At the end you don't do much heavy work on the UI thread, except updating the text view's text. As every thread is sleeping 1 second before updating the UI again, there should be no notable delay for the user as long as you don't run too many of those threads.
Im going through concurrency documentation and I can't quite understand what they mean with:
In an applet, the GUI-creation task must be launched from the init method using invokeAndWait; otherwise, init may return before the GUI is created, which may cause problems for a web browser launching an applet. In any other kind of program, scheduling the GUI-creation task is usually the last thing the initial thread does, so it doesn't matter whether it uses invokeLater or invokeAndWait.'
-What is the problem with the init being returned before GUI-creation?
-Why is the GUI-creation usually the last thing a thread does?
Tasks on the event dispatch thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive.'
-How can you make it finish faster?
http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TumbleItemProject/src/components/TumbleItem.java
-Where is the EDT in the above example?
SwingWorker worker = new SwingWorker<ImageIcon[], Void>() {
#Override
public ImageIcon[] doInBackground() {
final ImageIcon[] innerImgs = new ImageIcon[nimgs];
for (int i = 0; i < nimgs; i++) {
innerImgs[i] = loadImage(i+1);
}
return innerImgs;
}
#Override
public void done() {
//Remove the "Loading images" label.
animator.removeAll();
loopslot = -1;
try {
imgs = get();
} catch (InterruptedException ignore) {}
catch (java.util.concurrent.ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
};
-Why is initialisation of 'worker' here followed by the overwriting of several methods instead of just ';'? I have never seen this kind of notation before...
-Are all methods that aren't the 'doInBackGround()' method ,executed under the event dispatch thread?
'All concrete subclasses of SwingWorker implement doInBackground; implementation of done is optional.'
-In the code example ,I don't see a subclass for SwingWorker , unless new SwingWorker <>() , counts as a subclass?
'Be careful when invoking either overload of get from the event dispatch thread; until get returns, no GUI events are being processed, and the GUI is "frozen". Don't invoke get without arguments unless you are confident that the background task is complete or close to completion.'
-How would you use get() in a non-EDT way ?
My apologies if some questions are obvious and thank you for your time!
What is the problem with the init being returned before GUI-creation? -Why is the GUI-creation usually the last thing a thread does?
It says it right there in the text. "It might cause problems for browsers". It may be because the caller of init requires the method to create a GUI and schedule it for gui messages, and if none is created the caller fails.
How can you make it finish faster?
It's not about making the threads run faster, it's rather that if you have a long-going task, do it in a background thread instead of the event (GUI) thread as to not make it freeze.
Where is the EDT in the above example?
It's nowhere.. The applet has a EDT which is used when you for instance click a button or interact with the applet in other ways. I don't really understand your question here.
Why is initialisation of 'worker' here followed by the overwriting of several methods instead of just ';'? I have never seen this kind of notation before... -Are all methods that aren't the 'doInBackGround()' method ,executed under the event dispatch thread?
It's an anonymous class declaration of the SwitchWorker class. No, the doInBackground does not execute on the EDT, it's performed in the background. done is however scheduled on the EDT. See http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html for reference.
In the code example ,I don't see a subclass for SwingWorker , unless new SwingWorker <>() , counts as a subclass?
It does.
How would you use get() in a non-EDT way ?
As the documentation specifies:
get()
Waits if necessary for the computation to complete, and then retrieves its result.
So you should not call it until the background method completes, as to avoid freezing of the GUI.
I'm writing a chess program in java. So far things are coming along fine but I do have a problem with updating my UI.
Here's a snippet of code from class ChessBoard which extends JPanel. This is called when a user tries to make a move:
if ( isLegalMove( aMove ) ) { // If the move's legal
makeMove( aMove ); // Make that move
select = null; // Reset some info
drag = null;
toggleTurn(); // Change turns
generateMoves( 0 ); // Get legal moves for CPU
repaint(); // Redraw board
thread.run(); // Run chess algorithm
}
The thread is calling "run" on my instance of ChessBoard. The algorithm that finds the move can take several seconds to decide on a move.
I would like for my UI to update to reflect the user's move and then run the algorithm. That's why I run the algorithm on a separate thread. But my UI is not being updated until the computer also makes a move.
So if the user clicks a space to send a piece there, the screen freezes and then all of a sudden the piece has moved but the computer has moved also and it is again the player's turn.
Any help will be greatly appreciated.
thread.run() is going to execute the code in the thread's run method on the current thread. You want thread.start().
Relevant JavaDoc
The repaint method doesn't actually repaint immediately. It basically tells the JPanel that it ought to repaint itself soon. Then you go ahead on the same thread and calculate the AI's move, which will freeze the window because Swing isn't multi-threaded.
First, threads are not re-entrant (I'll explain that in a moment).
thread.run() is not causing the thread to execute in a separate thread, it's just call the run method of the thread (within the current Threads context.
What you need to do is set up a condition loop within your Thread that you can trigger in order to execute the logic you need.
public class ChessThread extends Thread { // I prefer Runnable, that's me
protected static final Object NEXT_MOVE_LOCK = Object();
public ChessThread() {
setDaemon(true); // This will allow the JVM to exit without the need to terminate the thread...
}
public void doNextMove() {
// Notify the "wait" that we want to continue calculating the next move
synchronized (NEXT_MOVE_LOCK) {
NEXT_MOVE_LOCK.notify();
}
}
public void run() {
while (true) {
// Wait for the "next move" request
synchronized (NEXT_MOVE_LOCK) {
try {
NEXT_MOVE_LOCK.wait();
} catch (InterruptedException exp) {
}
}
// Calculate the next move...
}
}
}
Now, Threads are non-reentrant, this means that once the run method has complete, that instance of the Thread can not be restarted.
Hence using thread.start() more then once will not work (can't remember if it throws an exception or not) (hence the reason I prefer Runnable)
So. What you want to do, is start the Thread when your program loads and when you need to, call thread.doNextMove() to cause it calculate the what ever it is you need.
Now, also remember, Swing is not Thread safe. That is, you should NEVER update the UI from any Thread other than the Event Dispatching Thread (or EDT)
You might also want to have a read through Concurrency in Swing
Oh and Concurrency in Java
Please explain invokeAndWait() method in SwingUtilities.I am unable to understand this.
Explain it very clearly. It would be of great help if you try out with an example.
Edited to add #noob's expansion of the question:
What's not clear about this?
Here's a modified usage example:
import javax.swing.SwingUtilities;
public class InvokeAndWaitStuff
{
public static void main(String[] args)
{
final Runnable doHelloWorld = new Runnable() {
public void run() {
System.out.println("Hello World on " + Thread.currentThread());
}
};
Thread appThread = new Thread() {
public void run() {
try {
SwingUtilities.invokeAndWait(doHelloWorld);
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("Finished on " + Thread.currentThread());
}
};
appThread.start();
}
}
Output:
Hello World on Thread[AWT-EventQueue-0,6,main]
Finished on Thread[Thread-0,5,main]
And why is this important?:
Causes doHelloWorld.run() to be
executed synchronously on the AWT
event dispatching thread. This call
blocks until all pending AWT events
have been processed and (then)
doHelloWorld.run() returns. This
method should be used when an
application thread needs to update the
GUI.
As far as I can tell, this is basically a bottleneck that forces GUI updates to be executed synchronously by a single thread, rather than asynchronously by multiple threads, which can potentially be unsafe.
To understand what invokeAndWait() does, you first need to understand the event/thread model of Swing.
Basically, everything that affects the GUI in any way must happen on a single thread. This is because experience shows that a multi-threaded GUI is impossible to get right.
In Swing, this special GUI thread is called the Event Dispatch Thread, or EDT. It is started as soon as a Swing top-level component is displayed, and it's bascially a worker thread that has a FIFO queue of event objects that it executes one after another.
When a Swing GUI needs to be drawn or updated, the JRE places an event on the EDT queue. User actions that cause listeners to be called start as events on the EDT queue. And (this is this is the important part) everything your program does that changes the GUI (like registering listeners, adding/removing GUI components or changing model data that the GUI displays) must be placed in the EDT queue, or the GUI can get corrupted.
And now for the finish: invokeAndWait() places the Runnable you pass to it into the EDT event queue and waits until the EDT has executed it. This should be used when a non-GUI thread needs to do something that affects the GUI, but also needs to wait until it is actually done before it can continue. If you just want to do something that affects the GUI but do not care when it is finished, you should instead use invokeLater().
I had a similar problem in a JTable. The program was blocked somewhere in "scrollRectToVisible" method. I have replaced the call by wrapping it in an invokeLater call.
The invokeAndWait did not resolve my block problem.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
table.scrollRectToVisible(r);
}
});
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