I want to write an tail like app. Now this app, scans a file for changes in the background and fires events in case something changed.
I want to run my application until the user requests to exit it by pressing ctrl + c (working by default). I do not want to create a lot of CPU load just by doing an endless while(true) loop like I'm doing ATM:
try {
// thread doing the monitoring
thread.start();
// forcing the programm not to exit
while (System.in.available() == 0) {
Thread.sleep(5000);
}
} catch (final IOException e) {
e.printStackTrace();
}
Does anyone know a more elegant/the right approach for this?
I'm not sure why you are using a thread in the first place, the 'tail' unix script is simply a while(true) loop with no exit condition. It watches the file and prints changes if any is detected. I think by default it pauses 1 second, so basically:
while(true) {
// Code goes here. Watch file, System.out.print if it changes
Thread.sleep(1000);
}
No need for a thread. But to answer the question about the best way to keep your app alive: Simply don't return from the thread's run() method. You don't have to join the thread, the application will stay in the foreground as long as it has one non-daemon running thread.
If you want to read the System.in without busy-waiting, that's very easy to achieve. InputStream has blocking semantics so all you need to to is call one of the read methods and it will block until there is input available. If you are scanning text input, I'd advise BufferedReader.readLine. Also, do that on the main thread, no point in starting another one.
Related
Summary
For some reason when I call SecondaryLoop.enter() on the AWT Event Dispatch Thread (EDT), it does not wait for SecondaryLoop.exit() to be called before unblocking.
Background
Since I think SecondaryLoop is not a very well-known class, I'll give a brief overview:
In general, it is a bad idea to have any long-executing or blocking code running on the EDT because then your app will not be responsive to any events until that code terminates. The EventQueue.createSecondaryLoop() allows you to create a new event loop that will handle events, allowing you to block the EDT without loss of responsiveness. This is what swing modal dialogs use to allow you to block your EDT while you wait for the dialog to be closed, but still allow controls on the dialog itself to be able to operate.
After creating your SecondaryLoop instance, you should be able to call enter() and it should block until exit() is called.
From the docs
This method can be called by any thread including the event dispatch thread. This thread will be blocked until the exit() method is called or the loop is terminated. A new secondary loop will be created on the event dispatch thread for dispatching events in either case.
I'm not entirely sure what it means when it says "or the loop is terminated" though. That could be my issue.
Test Code
The calling the enter() method on a thread other than EDT, blocks as I would expect:
System.out.println("Enter Loop");
Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop().enter();
System.out.println("Done (we should never get here)");
Output:
Enter Loop
However, if we call it on the EDT, it blocks for about a second, but then continues on:
System.out.println("Enter Loop");
try {
SwingUtilities.invokeAndWait(() -> Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop().enter());
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
System.out.println("Done (we should never get here)");
Output:
Enter Loop
Done (we should never get here)
Per the comment by tevemadar (thanks BTW), I have updated the code to prevent any sort of possible garbage collection issue:
//Storing loop in array as a quick hack to get past the
// "final or effectively final" issue when using this in the invokeAndWait
SecondaryLoop loop[] = new SecondaryLoop[1];
System.out.println("Enter Loop");
try {
SwingUtilities.invokeAndWait(() -> {
loop[0] = Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop();
loop[0].enter();
});
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
System.out.println("Done (we should never get here)");
//Just printing this to make sure that it is used after the invokeAndWait is done. This is just
//to make sure there isn't some sort of optimization thing that is deciding that we don't
//need this anymore and allowing the loop to be garbage collected
System.out.println(loop[0]);
Output:
Enter Loop
Done (we should never get here)
java.awt.WaitDispatchSupport#2401f4c3
So, while it was a good suggestion, that does not appear to be my issue.
This seems pretty contradictory to the documentation (and the whole purpose of SecondaryLoop to me. Am I missing something?
Environment
OS: Windows 10
Java:
C:\Program Files\Java\jre8\bin>java.exe -version
java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
Update
On a hunch, I tried adding a timer that continually adds more events to the EDT loop. It seems that adding the timer keeps the loop alive and makes it blocking:
//Add a keep alive timer which adds an event to the EDT for every 0.5 sec
new Timer(500, null).start();
System.out.println("Enter Loop");
try {
SwingUtilities.invokeAndWait(() -> Toolkit.getDefaultToolkit().getSystemEventQueue().createSecondaryLoop().enter());
} catch (InvocationTargetException | InterruptedException e) {
e.printStackTrace();
}
System.out.println("Done (we should never get here)");
With that code, it hangs as I expect, and if I put in some code that calls the exit() method on the loop after some time, it terminates as I would expect. So it seems that the loop must terminate itself once it has gone a certain amount of time without an event (but only if it was originally triggered from the EDT for some reason...).
I suppose I can add timers that do nothing whenever I need to use this feature, but that is definitely more of a work-around hack than a fix in my opinion.
Figured it out (at least this specific problem, I still have some more related issues, but I'm hoping I can figure them out on my own).
I decided to start debugging around in the java source code and I realized that my thread was getting unblocked due to this segment in java.awt.EventQueue:
/**
* Called from dispatchEvent() under a correct AccessControlContext
*/
private void dispatchEventImpl(final AWTEvent event, final Object src) {
event.isPosted = true;
if (event instanceof ActiveEvent) {
// This could become the sole method of dispatching in time.
setCurrentEventAndMostRecentTimeImpl(event);
((ActiveEvent)event).dispatch();
} else if (src instanceof Component) {
((Component)src).dispatchEvent(event);
event.dispatched();
} else if (src instanceof MenuComponent) {
((MenuComponent)src).dispatchEvent(event);
} else if (src instanceof TrayIcon) {
((TrayIcon)src).dispatchEvent(event);
} else if (src instanceof AWTAutoShutdown) {
if (noEvents()) {
dispatchThread.stopDispatching();
}
} else {
if (getEventLog().isLoggable(PlatformLogger.Level.FINE)) {
getEventLog().fine("Unable to dispatch event: " + event);
}
}
}
In my case src was AWTAutoShutdown, which resulted in my secondary loop to terminate before I called exit().
I found this article which explains that in order to make sure the event queue eventually terminates when all windows are disposed, awt determines when all components are no longer displayable and the event queue is empty, then waits for 1 second, then triggers the event with the AWTAutoShutdown class as the source which terminates the event queue and allows the JVM to terminate. That 1 second timeout is why I observed that it would hang for a little bit.
This explains why adding a timer made my code work (since I was adding an event every half second and the timeout for AWTAutoShutdown is 1 second, the event queue would be kept alive).
The use case for all of this is to basically create an EDT-safe semaphore that will allow events to keep being executed even when it's waited for on the EDT (which I use to display JavaFX dialogs from a Swing application and make it behave like a native swing modal dialog). So in my actual use case, this should work just fine (because there should always be some swing component displaying in my actual applications). However, I hadn't even actually tried out my actual use case. Being a big believer in TDD, I first focused on my JUnit tests, which didn't actually create any UI components.
So, I did a quick test with a little dummy app that does have a GUI, it works just fine. I'm just going to add my 500 ms timer into my unit tests and start it and stop it before each test.
After doing that, I'm still running into some issues with some of my tests, but my minimal verifiable example from my original question works just fine. I'll dig into the remaining test failures and hopefully figure them out on my own. If it seems to be a related issue, then I'll just add a new SO question and put a link to it here.
okay, so I'm working on a boardgame.
The first 'while loop' checks if the game is over, the inner 'while loop' is supposed to wait for the user input (squareSelector and rooSelector are my mouselisteners, 'k' and 's' are the input that are supposed to be returned by the listeners)
However the 'while loop' crashes my program and blocking my listeners from working.
I read up about this and found out that swing is single threaded and so my listeners can't work while the whileloop is active. However I need to wait for the input in order to avoid nullpointers.
Any ideas on how to solve this ? (as in a different approach, or how to make my loop wait for the input)
the gameloop
while(currentPlayer.haveIWon() == false){
//wait for input
while(!inputIsDone){
System.out.println("waiting for move");
System.out.println(squareSelector.isDone() + " " + rooSelector.isDone()) ;
checkInput() ;
if(squareSelector.isDone() && rooSelector.isDone()){
inputIsDone = true ;
}
}
//update board
currentPlayer.performMove(k, s);
rooSelector.setDone(false);
squareSelector.setDone(false);
inputIsDone = false ;
//currentPlayer.setInput(false);
//repaint
Main.getState().getComponent().repaint();
}
//display winnner thing
the checkInput method
public void checkInput(){
if(rooSelector.getSelected() != null){
k = rooSelector.getSelected() ;
}
if(squareSelector.getSelected() != null){
s = squareSelector.getSelected() ;
}
}
If you need more code to understand what's going on let me know and I will add more.
Swing is single-threaded. Due to its design, everything related to GUI must be done on Swing thread, also called event dispatch thread. It basically does one thing: looks at event queue and if there is a something, it handles it, and if not, goes to sleep. Every mouse move, key press, repaint etc. is really an event in the event queue.
If your game only reacts on GUI events and has no lengthy operations, you don't have to use anything special. You can write your logic without while so that it will not block, only react to events. However, this possibility entirely depends on what you are trying to implement.
If you have any operations that block the thread for a long time, you'll want to use separate threads for that. This way, what other threads do won't impact your GUI, but you'll need to be very careful to send data from one thread to another or to call something on another thread.
I am playing audio in background and I want the control of program to stay stand still till the audio playing is over for that I am using empty while loop as follows
while(isPlaying==true){};
mediaPlayer.stop();
as you can see while loop holds program control till audio is playing and after that next instruction is executed. This is working fine but I came to know that this is not a proper way to do this empty-while is expensive I am searching for alternative. Please Help.
Assuming your program is in Java (...why did you give it three language tags?) You have a few options. You could use a proper synchronization event, e.g.:
// fields
Object playerStopEvent = new Object();
boolean isPlaying;
// in your media player, when playback is complete:
synchronized (playerStopEvent) {
isPlaying = false;
playerStopEvent.notifyAll();
}
// elsewhere, when waiting for playback to complete:
synchronized (playerStopEvent) {
while (isPlaying) {
try {
playerStopEvent.wait();
} catch (InterruptedException x) {
// abort or ignore, up to you
}
}
}
mediaPlayer.stop();
See the official tutorial on Guarded Blocks for more examples.
You could also just have mediaPlayer call some callback when it is finished, and e.g. disable GUI components when you start playing and re-enable them when the finished callback is called (you could also use an event listener approach here).
Without more info, I recommend the latter, as it won't prevent you from doing other unrelated things (or keep your program from responding at all) while the player is playing, but the former may be more appropriate depending on your situation.
If it's in C or C++ the concept is the same. Use whatever equivalent of condition variables / events you have for the first option, or whatever equivalent of callbacks / listeners / signals+slots you have for the second.
well, in my humble opinion, it's better to use another implementation..
try to use thread so that it won't hang your program in there (it's a background audio afterall; you might want to do something else while the audio is playing)..
try to check this page out..
First thing is that you don't have to compare 2 Boolean fields that you have done in your code...
while(isPlaying==true){};
you can do so like..
while(isPlaying){};
and, now that you have told that you are using java, you can try this...
while(isPlaying){
Thread.sleep(1);
};
You may consider a sleep(time in milliseconds ). This will allow your thread executing while loop to sleep for specified milliseconds and then check the condition again.
while(isPlaying==true)
{
Thread.currentThread().sleep(1000); // sleep for 1 sec
};
This once is quick but the better way is to use some wait() and notify() mechanism as suggested by #JasonC in his answer.
You really don't need the {} in your empty while loop.
while(isPlaying); would suffice.
Also, as others have already suggested, consider using a delay inside your loop, i.e.
Thread.sleep(100); // sleeps for 1/10 of a seconds in Java
Or
delay(100); // leeps for 1/10 of a seconds in Java
The simple way is that put sleep(1) in while loop. And cpu usage won't take more.
I want to recognize if a user sent a text, using readline method from BufferedReader. While the user didn't send anything, the Thread keeps sleeping. Is there a way to do this? I'm trying for a long time, but no success yet.. I guess I have to recognize if a ENTER key was pressed.. but I donwt know how to do this.. The interface of my program is the console..
The problem is: I have a client-server program. When a client enters a message, the message prompts on the screen of the another user/client. But, if the user doesn't send a message in 10 seconds, I want a message to appear on the screen.. So I have a Thread.sleep(1000). The problem is I don't know when to wakeuo the Thread.
while((mensagem == null) || (!mensagem.trim().equals(""))) {
Thread.sleep(10000);
sendToAll(output, "[Your turn] ", "");
mensagem = input.readLine();
}
The last line isn't correct also, because I don't want to force the user to type, and this way I'm forcing, 'cause I stop on input.readLine().
SOLUTION:
I resolved the problem using the method setSoTimeout(10000).. This is the code:
public Server(Socket socket) throws SocketException{
this.connection = socket;
this.connection.setSoTimeout(10000);
}
public void run(){
[...]
while((msg != null) && !(msg.trim().equals(""))){
try{
msg = input.readLine();
sendToAll(output, ": ", msg);
} catch (SocketTimeoutException e) {
sendToAll(output, "Time out ", "");
}
}
Thank you all for the ideas!! :)
You read entire lines like this:
String in;
while ((in = br.readLine()) != null) {
// If this is triggered, in contains a whole line and if the input came from console that means enter was pressed
}
Edit: responding to your edit:
input.readLine() is a blocking method. It will continue to attempt read a full line until a line is received, exception thrown, or EOF is reached. Your issue is that you want a 10 seconds timeout. Correct me if I'm wrong.
The way to do this is to create a timer or a thread that isn't blocked by the call to interrupt your .readLine() call. You should have all I/O in its own thread already, so from another thread (main thread, or using a Timer) you need to create a timed event that will interrupt the blocked thread. Example using Timer, add this right before the loop:
java.util.Timer t = new java.util.Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
IOHandlerClass.this.interrupt();
}
}, 10000);
Substitute IOHandlerClass with the name of the class that this code is put inside (you didn't post your code, so I don't know the name).
Now, this will cause an InterruptException to be thrown after 10 seconds unless you stop the timer. So, surround your code with a try-catch to catch that exception and if it's thrown you display the error message. Remember to cancel the timer if you do infact get valid response within the 10 seconds timeout.
You need to understand what is going on here, on both the Java side and the console side.
On the Java side, the readLine() call is simply attempting to read characters until it sees either a valid "end of line" sequence, the end of the input stream. It is a blocking call, and there is no way to specify a timeout in the API that you are using.
On the Console side, console is watching for keyboard events and accumulating them in a line buffer:
When it sees a key event for a data character (a digit, letter, whatever), it adds the character to the buffer.
When it sees a meta character (e.g. a "delete") it performs the appropriate edit on the line buffer. For example, it might delete a character from the line buffer at the 'cursor' position.
When it sees an ENTER key, it adds an end-of-line sequence to the line buffer, and sends the line.
Details will depend on the console program and how the user has configured it. However, the fact remains that until the user types ENTER, nothing will be sent to the "pipe" that connects the console to the Java application. In short, the Java application won't see anything.
What this means is that the Java application can't tell if the user is typing or not.
So what can the Java application do?
You could use a Timer to send an interrupt to the blocked Java thread (the one doing the readLine() call) after a few seconds / minutes. This will cause the readLine() call to unblock and throw an IOException. However, there are problem with this approach:
There is a potential race condition where the timer fires after the readLine() call finishes, and the interrupt goes to application itself. This could cause problems, depending on what the application does with interrupts. You should be able to avoid this using a properly synchronized flag that the primary thread sets when the readLine call returns.
It is not entirely clear, but there are signs that if you get an interrupt on a pipe, the underlying channel is automatically closed. That would mean that you couldn't ask the user for any more input.
The second approach might be to replace your BufferedReader / readLine() code with something that uses NIO channel selectors. Among other things, a Selector allows you to wait with a timeout for a channel to have readable data. You'd then need to implement buffering and readline on top of that.
If you wanted to know if the user had typed at the console, you'd need to put the console into non-line-editing mode. This cannot be done in pure Java, but there are 3rd-party libraries that do this kind of thing.
How to add return statement to watchable method in Java and still be working properly. I want always to be searching for files, OK I have that. But now I want to get the return, but when I add return statement everything goes down the function stops and the watchable stops too .. Any ideas ?
for (;;) {
WatchKey key = watcher.take();
for (WatchEvent<?> event: key.pollEvents()) {
if (event.kind() == StandardWatchEventKind.ENTRY_CREATE) {
System.out.println(event.context().toString());
}
}
Here is the loop which always searches, how to return from It and still to be working?
I think you mean you want to perform other actions in the program, while still having the watcher run. For that, you would need to create and start a new Thread for the watcher:
Thread watcherThread = new Thread(new Runnable() {
public void run() {
// Watcher loop code goes here
}
});
watcherThread.start();
As #dlev says, if you want your application to process watch events at the same time as it is doing other things, then the way to do it is in a separate thread.
This leaves you with the problem of "returning" the information. (I presume that simply printing the information to standard output is not any use to you.)
As you observed, you can't use return because that will terminate the loop.
The basic answer is that you need to put the information somewhere so that the rest of your application can access. For example:
You could create a queue object (e.g. a ConcurrentLinkedQueue), have your watcher enqueue the data, and have some other thread dequeue it and process it.
You could have the watcher process the event payload itself and put the results into a shared data structure.
However, without more information, it is difficult to decide what approach will be best for you.