I wanted to build a search that shows you the results when the user finishes writing.
If I had to search in a local db I would have triggered the search every time the user releases a key.
In my case I have to send Web Requests to an API point that exposes the search function. The server allows only 20requests per minute from a single IP.
So, I wrote a Thread that detects when user really finishes writing:
(while true)
save the searchbox text
wait for 400ms
check if the searchbox text is the same as the one saved before
Code:
private void checkIfUserFinishedWritingFunction() {
while(true) {
String previousText = textField.getText();
try {
Thread.sleep(400);
} catch (InterruptedException ex) {
return;
}
String actualText = textField.getText();
//WHEN USER FINISHED WRITING...
if(previousText.equals(actualText)) {
//IF SEARCHBOX ISN'T EMPTY
if(!textField.getText().trim().isEmpty()) {
//START A THREAD THAT SENDS WEB REQUEST
}
//IF SEARCHBOX IS EMPTY...
else {
//HIDE RESULTS POPUP
if(resultsList.isShowing())
resultsList.hide();
}
return;
}}}
NetBeans is telling me that Thread.sleep() called in loop could be dangerous. I think it's because of the cost, and in my the loop runs every 400ms.
How can I fix this algorithm?
I think it's because of the cost, and in my the loop runs every 400ms.
Actually, it is because when you call sleep in a GUI-based application, you are liable to cause the event listener thread to freeze.
(And if this is not on the event listener thread, then calling hide is probably a thread-safety hazard.)
A better alternative would be to use a combination of an event listener for update events on the text box that pays attention to the time since the last query you sent, and something like a ScheduledExecutorService.
Calling Thread.sleep() isn't costly, but creating a thread might be.
As a rule of thumb, if you write code that calls sleep(), then you are either (A) trying to do something that nobody's ever thought of before, or (B) re-inventing something you could have had for free, or (C) making a mistake.
For most of us, it's usually (B) or (C) or both.
In this case, instead of dedicating a thread to polling the GUI state, you could do the polling from within the Event Dispatch Thread (EDT) itself by using a javax.swing.Timer. See the Java tutorials for examples: https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
Related
I am developing a java project where an external microcontroller device is connected via serial port to the computer. I have a wait dialog in the java application, waiting for a command to execute on the microcontroller device. If the microcontroller doesn't respond within 10 seconds the application shuts down.
The problem is that some commands are too fast, and the microcontroller responds before the wait dialog becomes active. This causes the application to shutdown after ten seconds.
Here is the first idea I thought to wait for the dialog to be visible:
new Thread() {
public void run() {
while (!Main.mainFrame.waitDialog.isVisible()) {}
Main.usbManager.start();
}
}.start();
But the application is stuck in the while loop and the wait dialog is visible, but if I add some random sentence to the while loop, for example, System.out.flush();, it works and when the dialog is visible the program exits from the while loop.
How can I wait for the dialog to be visible?
Thanks
Most GUI libraries are single threaded. This means that calls to it might not be thread safe, you are never guaranteed to see a change. In particular boolean values can be inlined, so you can be sure after a certain point you won't see a change in the value.
If you use something which slows down the loop, it won't optimise the code for a while (this is unreliable) or has a memory barrier like System.out.flush() does, then this optimisation won't occur.
A better way to poll might be to use Thread.yield() or Thread.sleep(40) to save yourself some CPU as well.
I think there is a problem with the .isVisible() method and a general fail usage of while loop.
if I add some random sentence to the while loop, for example, System.out.flush();, it works
There is a question with a similiar problem "Why does while(true) loop just run once - Java" on the while loop
it runs with random method like System.out.println()
I think you should call something when the actual window in the other thread closes in this thread, so you don't have to wait.
Suppose I have a nametag, which is UI component in GUI program.
The nametag will constantly change its text based on the data.
If the user change his/her name data, then he/she will see the change in nametag.
For this task, my code looks like this:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
String name = data.getName();
nametag.setText(name);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Since the reaction time of 0.1s seems instant to people, I included Thread.sleep(100) for computer to take a break.
However, I am not sure if that helps the computer in terms of energy usage or something. Is sleep method in this case complete waste of time? No benefit at all?
Thread.Sleep has been used for many things it shouldn’t be used for.
Here’s a list of the common mistakes:
The thread needs to wait for another thread to complete
In this case no value, other than infinite, passed to Thread.Sleep will be correct. You simply don’t know when the other thread will complete using this method. If the thread completed after Sleep returned you’ll likely have synchronization problems. If the other thread completed before Sleep returned the thread was needlessly blocked for an amount of time rendering the benefits of multithreading limited or moot. In the control circumstances where you’ve tested this it may seem like it always works; it just takes a busy program to cause it to faile: a defrag program, a sudden influx of network traffic, a network hiccup, etc.
The thread needs perform logic every n milliseconds
As noted earlier, Sleep means relinquish control. When your thread gets control again isn’t up to the thread; so it can’t be used for periodic logic.
We don’t know why Thread.Sleep is required; but if we take it out the application stops working
This is flawed logic because the application still doesn’t work with Thread.Sleep. This is really just spackling over the problem on that particular computer. The original problem is likely a timing/synchronization issue, ignoring it by hiding it with Thread.Sleep is only going to delay the problem and make it occur in random, hard to reproduce ways.
Source: http://blogs.msmvps.com/peterritchie/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program/
This doesn't answer your direct question, but it does help address an XY Problem component of your question:
It looks like you're listening for object state changes by polling: by constantly testing an object to see what its state is and whether it's changed, and this is a bad idea, especially when coding for an event-driven GUI. Much better to use an observer pattern and be notified of state changes when or if they occur. That is how the Swing GUI library itself was written, and you should strongly consider emulating this.
Some ways to be notified of changes are to use component event listeners which can listen for changes to Swing components, such as ActionListeners, ChangeListeners, ItemListeners, and the like. Another way when listening to non Swing component items is to use SwingPropertyChangeSupport and PropertyChangeListeners and in this way to create "bound" properties of your class. This is often used for non-GUI model classes.
I am trying to build a simple tictactoe network game. I need the program to wait until a player makes a move and then continue. In my whileConnected() function at the bottom of my code, I have a while(true) cycle that is supposed to run forever and display a confirmation message when the button is pressed (which is signaled by the fact that the content of the String variable 'message' changes).
The problem is that even if the String message variable changes when the button is clicked, my whileConnected() function never realizes this and the if statement inside the function never evaluates to true. An identical if statement inside the ButtonListener class works fine and displays the desired confirmation message.
How can I solve this problem? I've read and read and I get the idea that I should use Threads (I read about them but I never used them before, that's why it's only a guess). Do I need threads? Can someone explain in short the principle that should be used for this specific problem? (how can I make the program pause until the button is clicked and then continue using relevant information created when the button was clicked). A code example would really lighten up my reading about threads - which is a really abstract topic when one is a beginner.
Below is my code, thanks in advance.
public class Test extends JFrame
{
private Container contentPane;
private JButton btn00;
private static String message = "";
private class ButtonListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
String buttonText = e.getActionCommand();
if (buttonText.equals("My Button"))
{
message = "pressed";
if (message != "")
System.out.println(message+"(executed by ButtonListener)");
}
}
}
public Test()
{
this.contentPane = this.getContentPane();
btn00 = new JButton("My Button");
btn00.setSize(btn00.getPreferredSize());
btn00.setLocation(20,20);
ButtonListener listener = new ButtonListener();
btn00.addActionListener(listener);
// configure frame
this.setSize(300,300);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
// make panel
JPanel panel = new JPanel();
panel.setSize(200,200);
panel.setLocation(10,10);
panel.add(btn00);
this.contentPane.add(panel);
}
public static void main(String[] args)
{
Test gui = new Test();
gui.setVisible(true);
// connected
whileConnected();
}
private static void whileConnected()
{
System.out.println("message is at first empty: "+message);
while (true)
{
// the if below never evaluates to true... why?
if (message != "") // this is never true
System.out.println(message+"(executed by whileConnected)");
}
}
}
If you're using swing, you're already using threads. Swing by its nature has a thread for I/O and a thread for back-end. You do indeed want to use threads here - among other things, putting a thread in wait is a lot cheaper than giving it an infinite loop to churn on.
Listeners are another application of threads, and I wouldn't be surprised if you could get most or all of what you want just by using well-constructed listeners. Alternately, there are these things called semaphores. Semaphores are a way for threads to handle timing - if a thread attempts to lock a semaphore that's already locked, it will wait until another thread unlocks it before continuing (and locking it again). In your case, you might try the following.
Have a button listener, a main function, and a locked semaphore.
Main function starts, does any initial behaviors, and attempts to grab semaphore. since the semaphore is already locked, it holds.
When the button listener fires, one of the things it does is unlock the semaphore.
As soon as the semaphore unlocks, the main function grabs it (thus locking it once more) and does whatever it's supposed to do. Eventually, it finishes that, and attempts to grab the (locked) semaphore again, thus waiting for the next time the button listener fires.
repeat.
Edit: To include and explain the actual accepted solution (from comments below).
Fix: add Thread.sleep(1000); to the inside of the while loop in the whileConnected function.
Explanation: The while loop is an infinite loop that contains nothing but an if statement. This if statement evaluates to false (and therefore does nothing further) for a really long time (at least as far as the computer is concerned). This acts in much the same way an electrical short does - there's nothing to slow it down, so the thread that runs that main function burns up a lot of computing resources doing nothing. This is bad. It is possible that some failsafe kicked in and killed the thread. It is possible that the thread failed or broke something in an uglier manner. In any case, including a sleep statement (in this case, sleeping for a second each loop, as it's measured in ms) prevents this, and thus allows the function to continue indefinitely.
Swing, like most GUI frameworks, is an event driven environment. Basically this means, the application will wait for some kind of event to occur and then will trigger any registered listeners tha are waiting for notification for that event.
In your case, you would simply need to register a AdtionListener to the button. When the user clicks it (or activates via the keyboard), the actionPerformed method will be called and you can execute what ever code you need.
Check out How to write action listeners for more info.
Swing is also a single threaded framwework. That is, all interaction with the UI must be executed from within the context of the Event Dispatching Thread.
This also means, that any long running or blocking task MUST be executed from a separate thread so as not to block the EDT from processing incoming events and repaint request, which could make you application appear as if it has hung.
Check out Concurrency in Swing for more details
To my mind, your game protocol is going to need some way of tracking whose round it is. This would be achieved simply via the use if a virtual token.
The basic concept would be, unless the player has the token, they can't make a move. Once the player makes a move, that move and the token is sent to the other player.
I think by definition the Game is paused until the button is pressed, as the gui will not be running the the main thread, it should be running in the event dispatching thread.
Swing certainly has a number of gotchas around threading and listeners that can result in some unpredictable behaviour when not implemented correctly.
Have you gone through the Java tutorials on oracle for Swing? Most relavent would be the examples in http://docs.oracle.com/javase/tutorial/uiswing/events/index.html for Listeners and http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html for WorkerThreads
I've found with Swing the best thing is to download the examples here and try to expand on them
I agree with Ben Barden though, from my understanding of what you need, I think you can achieve what you need using listeners.
I am new to Java concurrecny and I am reading this at the moment: Java Tutorial-Interrupts But I can't really understand where and why I should use an Interrupt. Can someone give me an example (code) so I better understand it? thx
Interrupts are used when you want to (cough) interrupt the thread -- typically meaning stop it from operating. Thread.stop() has been deprecated because of various issues so Thread.interrupt() is the way that you tell the thread that it should cease running -- it should cleanup what it is doing and quit. In reality, the programmer can use the interrupt signal on a thread in any way that they want.
Some examples:
Your thread might be sleeping for a minute and then spidering a web-page. You want it to stop this behavior.
Maybe you have a thread which is consuming from a queue of jobs and you want to tell it that no more jobs are coming its way.
Maybe you have a number of background threads that you want to interrupt because the process is shutting down and you want to do so cleanly.
There are certainly many ways to accomplish the above signaling but interrupt can be used.
One of the more powerful ways that Thread.interrupt() affects a running thread is by throwing InterruptedException from a couple different methods including Thread.sleep(), Object.wait(), and others.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// i've been interrupted
// catching InterruptedException clears the interrupt status on the thread
// so a good pattern is to re-interrupt the thread
Thread.currentThread().interrupt();
// but maybe we want to just kill the thread
return;
}
Also, often in a thread we are looping doing some task and so we check for interrupt status:
while (!Thread.currentThread().isInterrupted()) {
// keep doing our task until we are interrupted
}
With multi-threading, the idea is that you have some work that you divide up among several threads. The classic example would be to have a thread that does a background calculation or a background action such as a server query that will take a fair amount of time without doing that action in the main thread that handles the user interface.
By offloading those actions that might take a noticeable amount of time, you can prevent the user interface from seeming to get stuck. An example of this would be when you start an action in a displayed dialog, go to another window then return to the displayed dialog and the dialog does not update itself when you click on it.
Sometimes the background activity needs to be stopped. In that case you would use the Thread.interrupt() method to request that the thread stop itself.
An example might be if you have a client that is getting status information from a server once a second. The background thread handles the communication to the server and getting the data. The user interface thread takes the data and updates the display. Then the user presses a Stop or Cancel button on the display. The user interface thread then does an interrupt on the background thread so that it will stop requesting the status information from the server.
In concurrent programming, many programmers arrive at the conclusion that they need to stop a thread. They decide it would be a good idea to have some sort of boolean flag to tell indicate to the thread that it should stop. The interrupt flag is that boolean mechanism provided through the Java standard library.
For example:
class LongIterativeTask implements Runnable {
public void run() {
while (!thread.isInterrupted()) { //while not interrupted
//do an iteration of a long task
}
}
}
class LongSequentialTask implements Runnable {
public void run() {
//do some work
if (!thread.isInterrupted()) { //check flag before starting long process
//do a lot of long work that needs to be done in one pass
}
// do some stuff to setup for next step
if (!thread.isInterrupted()) { //check flag before starting long process
//do the next step of long work that needs to be done in one pass
}
}
}
I never gave the use of Thread.Sleep much thought, until I downloaded the latest version of Netbeans. Netbeans now warns you not to use Thread.Sleep. So I did some research on the topic and found people stating that you only need to use Thread.Sleep for debugging/testing purposes and that if you use it at any other time you have poorly written code.
So my question is how can I keep from using Thread.Sleep in the following situation.
I have written a server application that interfaces with another application. The server has two threads:
Handles the data coming over the socket and sends back other information or just plain acknoledgements.
This is the main thread. After kicking off the socket thread it going into an indefinite while loop. Within this while loop I check to make sure the socket thread is still active and that the user hasn't asked to exit the application via a TrayIcon interface. Then I sleep and continue this while loop.
With this application, the TrayIcon is the only UI.
Here is the snippet I'm referencing:
// continues running as long as the exitth file is not present and
// the tray icon is not in a safe to exit status.
while(doNotExit())
{
if (getPrimaryThread() == null || !getPrimaryThread().isAlive())
resetsThreadAndSocket();
try
{
// check to see if the socket threads are still active, if not create new ones.
if ((getPrimaryThread() == null || !getPrimaryThread().isAlive()))
createSocketThread();
// check right before sleeping that the user does not want to exit.
if(getTrayIcon().isExiting())
break;
// puts the main Thread to sleep for 3 seconds
Thread.sleep(3000);
}
catch(SQLException ex)
{
_log.error(ex.getMessage(), ex);
restartDatabase();
}
}
The 'preferred' method in most cases would be to use the ScheduledExecutorService built into JavaSE for performing a periodic task, rather than reimplementing it yourself every time using a while loop and Thread.Sleep().
There's nothing wrong per-se with your example. The language just now has a much more robust support for doing that built into it as of Java 5.
Instead of your Thread.sleep(3000) do:
getPrimaryThread().join(3000)
This will wait for the thread to exit for 3 seconds.
You should consider attaching an event listener to your tray icon instead of polling its state. That way you won't need an extra thread just for monitoring.
If you can't do that for some reason, you can still do away with the extra thread as the Timer class can do the waiting for you.
You seem to be paranoid that some condition (maybe a RuntimeException or Error?) is going to cause your socket Thread to just die. Ideally, you would design your Socket Thread such that it protected itself from crashing. The following example creates a loop that can only be broken as a result of a JVM Error or Thread interrupt:
public void run() {
while(!Thread.currentThread.isInterrupted()) {
try {
//you application logic
} catch (RuntimeException e) {
//log uncaught exception
}
}
}
In order to shutdown the application, you would attach a listener to the TrayIcon which contained a reference to the SocketThread and could stop it by simply interrupting it.
socketThread.interrupt();
I'll leave figuring how to add an ActionListener to a TrayIcon up to you.