Inside a method, I start a thread that waits for user input (swing pushbutton).
Only after that input, the thread can be closed and the method returns a value.
My problem is that the code waiting for the input is not run inside that thread, but elsewhere:
String returnString = "";
Thread waitThread = new Thread(
() -> {
while (xy == null) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw THREAD_INTERRUPTED.toException();
}
}
}, "waitThread"
);
waitThread.start();
try {
waitThread.join();
} catch (InterruptedException e) {
throw THREAD_INTERRUPTED.toException();
}
// -> wait for user input -> xy != null -> waitThread ends -> main thread joins -> continue code:
returnString = xy;
return ReturnString;
Why is this necessary? Because the method has to return the value (xy) that is set elsewhere by clicking a pushbutton.
The code above just ends up in an infinity loop, not allowing any interaction with the swing components.
Not being a pro in swing, I suppose the main thread is meant to catch interaction events. Since it is stuck in the waitThread.join(); , thats not possible. Correct?
Is there a way to restructure this?
Why reinvent the wheel? Plenty of ways to do this out-of-the-box:
public static void main(String[] args) {
String message = JOptionPane.showInputDialog("What are you gonna tell me?");
System.out.println(message);
}
I think you are going down the wrong route.
Clicking a button leads to an event, and then there should be an ActionListener reacting to that.
And that listener could update some "statish" thingy, and your other thread is reading that information.
To answer jannis' question: The method opens a popup window that holds lets say two buttons. Each button sets a specific return value for the popup, which is then returned by the same method. So the method needs to open and close the popup. I know this is stupid, but it has to be this way. The setup would work, if I could keep interaction with the frontend enabled while waiting somehow.
Judging from this comment you seem to be trying to rediscover what is called a "modal dialog" and it's not stupid, at all. Please see the official documentation about dialogs in Swing: How to Make Dialogs
.
Related
I've just put together one of my first full Java programs for practice. It is a simple snap game but I'm not happy with the method for the actual "Snap" condition. I may be being fussy but I wonder if there is something better someone could suggest?
public static boolean snap() {
Scanner response = new Scanner(System.in);
double compReflex = (Math.random() * (1000 - 250 + 1)) + 250;
long reflex = Math.round(compReflex);
long startTime = System.currentTimeMillis();
System.out.println("go");
response.nextLine();
if (System.currentTimeMillis() > startTime + reflex) {
System.out.println("I win");
response.close();
return false;
} else {
System.out.println(System.currentTimeMillis() - startTime);
System.out.println("Well done");
response.close();
return true;
}
}
The issue is I would like the else clause to happen immediately if a button was pressed and the if=True clause to happen automatically after the reflex delay if the button isn't pressed. At the moment enter has to be pressed and then the computer judges who had the shortest reaction time. Which isn't snap...
I looked at KeyListeners but they only seem to be available for UI's such as JSwing? I also looked at thread interruption but couldn't work out how to trigger a thread interrupt and then handle the exceptions with the correct program flow? Or is it is even possible?
I think it needs to be a multi-threaded solution but don't fully have a handle on concurrency/multi-threading yet so any really good learning resources appreciated in addition to solutions.
If the console API weren't so dreadfully old, you could simply do something like
try {
System.in.readLine(100, TimeUnit.MILLIS);
System.out.println("You win!");
} catch (InterruptedException e) {
System.out.println("Too slow!");
}
but unfortunately, the API to read from a console was defined in the very first release of the Java programming language, and not reworked since, so it doesn't allow reading with a timeout. If a thread reads from an InputStream, it won't stop reading until there is data, the InputStream itself signals an error, or the entire JVM exits.
So if you really want to do this, you'd need something like this:
public static void main(String[] args) {
var readerThread = new Thread(() -> {
try (var scanner = new Scanner(System.in)) {
scanner.nextLine();
gameOver(true);
}
});
readerThread.setDaemon(true); // this thread should not inhibit JVM termination
readerThread.start();
System.out.println("Go!");
sleep(500, TimeUnit.MILLISECONDS);
gameOver(false);
}
static void sleep(int duration, TimeUnit unit) {
try {
Thread.sleep(unit.toMillis(duration));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
synchronized static void gameOver(boolean victory) {
if (!over) {
System.out.println(victory ? "You win!" : "I win!");
over = true;
}
}
static boolean over;
A few things to note here:
Since the two threads race to gameOver, we need to ensure they don't both execute it. By making the method synchronized, we ensure that the threads will execute it after each other, and by setting a boolean, we can detect whether the other thread was faster.
everything is static because we can't cancel the reading thread. Granted, we could keep it running and reuse it for the next instance of the game, but it would eat any console input in the meantime (such as the answer to "do you want to try again?"), which is annoying. So I am not going to pretend that this solution is nice and reusable, and thus can make my life easier by making everything static.
the try-with-resources statement is a compact way to close a resource (such as a Scanner) once we are done with it.
the utility method for sleep is just to move the pointless, but required, catch block out of the main method, so the main method is easier to read.
So I got this new game I am coding.
Long story short, there is a textarea in my GUI which acts as an event displayer. When you fight a monster, this textarea is used to display lines of text such as "You deal 3 damages to skeleton" or "Skeleton casts fireball on you and hit you for 5 damages".
The code works in a way so that the monster attacks after you. So as soon as you hit the "Attack" button, both the line saying what you did and the line saying what the monster did appears at the same time in the textarea. Like if the monster could hit you at the speed of light right after you hit it.
What I want to do is to delay the display of the monster's line. So that when I hit the "Attack" button, the textarea displays the line of what I did, then wait a second and then displays the monster's line.
I tried using the Thread.sleep() method, but all it does is pausing the UI for 1 second and then both lines appear in the textarea.
private void attackBareFists() {
if (initPJ > enemyINIT) { // Player has more initiative ->
// Player attacks first
turnPlayerBareFists(); // This method will display the player's line
if (!endTurn()) { // endTurn() checks that the player or the monster
// are still alive before continuing the fight
delay();
turnMonster(); // This method will display the monster's line
endTurn();
}
} ... // The code continues, but it's the same as above except monster attacks first
}
/**
* Wait for some time
*/
private void delay(){
}
What should I put in delay()? This is where I've tried Thread.sleep(1000). And like I said, doing so caused the code of turnPlayerBareFists() and turnMonster() to be executed after delay(). Any help would be appreciated.
I think a better/more consistent way to achieve this is by using timers. You could use any java implementation, though javafx itself provides several mechanism for timed events.
One way is the TimeLine
Timeline timeline = new Timeline(new KeyFrame(
Duration.millis(1000),
ae -> doSkellyTurn()),
new KeyFrame(
Duration.millis(1000 + 1000), // as mentioned by fabien, the time offset is relative to the 'start()' method, not to its previous keyframe!
ae -> endSkellyTurn()));
timeline.play();
The above way is also the basics for javafx animations (as you can read in the documentation)
This blog shows some more examples of how you can accomplish timed tasks. (Ps. It uses reactFX as well!)
Great question! I suggest using something like this:
public static void delay(long delayMs, Runnable toRun){
Thread t = new Thread(() ->{
try { Thread.sleep(delayMs); }catch(InterruptedException ignored){}
Platform.runLater(toRun);
});
t.setDaemon(true);
t.start();
}
This way, you can specify exactly how long the delay should between the call to delay() and when your code should be executed. Essentially you pass a Runnable containing whatever code you want to run as the second argument of the method.
For example, this would mean that your the monster's turn would be represented as such:
if(!endTurn())
delay(1000, ()->{ turnMonster(); endTurn(); });
If, for some reason, you don't want to use lambdas (the "()->" things), you can use this:
public static void delay(long delayMs, Runnable toRun){
Thread t = new Thread(new Runnable(){
public void run(){
try { Thread.sleep(delayMs); }catch(InterruptedException ignored){}
Platform.runLater(toRun);
}
});
t.setDaemon(true);
t.start();
}
And your monster code would look like this:
if(!endTurn())
delay(1000, new Runnable(){ public void run(){ turnMonster(); endTurn(); } });
If you're wondering, Platform refers to javafx.application.Platform and the runLater() method will always post the given Runnable to the JavaFX thread, so it's safe to pass it code that manipulates the UI.
Alright, before this gets flagged as a possible duplicate, I've already tried the following code:
Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK)
And it is always returning false for me [see below]. Could someone confirm if this is supposed to be working, and I'm misusing it, or if it's known to be broken? If it is in fact broken, does anyone have a better method to use?
EDIT:
Alright, just found out something more. It appears to just return what it was at the begining of my programs launch. If I start the program with it on, it says its on, and vice versa. Here's my code:
while (true) {
boolean isOn = Toolkit.getDefaultToolkit().getLockingKeyState(
KeyEvent.VK_CAPS_LOCK);
System.out.println("Caps lock is now: " + (isOn ? "ON" : "off"));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
And that's just always printing out whatever it started as
(ex. if I start with caps lock on, even if I toggle it off right after, it prints:
Caps lock is now: ON
Caps lock is now: ON
Caps lock is now: ON
Caps lock is now: ON
etc., if I start with it off, it will print off no matter what)
Poking around, I think getLockingKeyState() might be broken.
You could try KeyboardUtils, but it looks like that means you have to carry JNA overhead.
Looks like this was always broken or at least since Java 1.3 (see Bug 4414164).
Not sure for other platforms, but for Windows I can say this: State change of Caps Lock can be detected, but only if your awt client has the focus. However, there is this workaround which works for me:
boolean isCapsLockOn() {
java.awt.Robot robot = new java.awt.Robot();
robot.keyPress(KeyEvent.VK_CONTROL);
robot.keyRelease(KeyEvent.VK_CONTROL);
return Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK);
}
Contraint: Your awt app must have the focus before calling isCapsLockOn.
Note: Your robot might press any other key which is not harmful to your app. Might depend on your use case.
public void checkOnOff() {
Thread th = new Thread() {
public void run() {
for (;;) {
if (Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK)) {
jLabel4.setForeground(Color.red);
jLabel4.setText("CAPSLOCK is ON");
} else {
jLabel4.setText(null);
}
try {
sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Login.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};th.start();
}
I thought I understood EDQ until I hit this problem. I have the code shown below. It reads from a Bufferred reader. If the first character received is a "Z" I execute one set of code (displaying a JOptionPane) and if it is a 0 I execute another section of code (displaying another JOptionPane). I am trying to do this within the EDQ and so I use SwingUtilities invokeAndWait. When I test these error conditions, the first statement in the conditional works as designed, but I get a java error when testing the else clause. Specifically:
Exception in thread "AWT-EventQueue-2" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread
at java.awt.EventQueue.invokeAndWait(Unknown Source)
It is all part of the same conditional. How can one clause be part of the EDQ and another clause not be.
This is crazy.
Thanks for any help.
Elliott
while ((line = in.readLine()) != null) {
if (line.charAt(0) == 'Z') {
String theMsg;
theMsg = "No records were found.";
try {
SwingUtilities.invokeAndWait(new DoShowDialog(null, theMsg, 0));
} catch (java.lang.reflect.InvocationTargetException e1) {
e1.printStackTrace();
} catch (InterruptedException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
noDocs = true;
Object args[] = new Object[1];
args[0] = "1";
window.call("uploadConfig", args);
downloadAccount.setEnabled(true);
uploadAccount.setEnabled(false);
deleteAllUnselectedCodes.setEnabled(false);
queue = null;
if (poll) {
polltimer.restart();
}
} else if (line.charAt(0) == 'O') {
String theMsg;
theMsg = "Account is currently checked out
by user "+ line.substring(1)
+ ". You can view this
account but you cannot modify it. ";
try {
SwingUtilities.invokeAndWait(new DoShowDialog(null, theMsg, 0));
} catch (java.lang.reflect.InvocationTargetException e1) {
e1.printStackTrace();
} catch (InterruptedException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
initialckBoxState = false;
accountfoundandnotcheckedout = true;
viewMode = true;
patientpane.setEditFields(false);
otherpane.setEditFields(false);
getAccountImages(acctEntered); // bluenoble
}
.....................
more stuff
}
Execution doesn't jump threads.
Thus all the code posted runs in the EDT (Event Dispatch Thread) and it refuses to invokeAndWait because that causes an inherent deadlock. (Actually, it could be turned into an invoke-immediate as done with SynchronizationContexts in .NET, but it was not designed as such.)
In this particular case I suspect the code is invoked from within an EDT callback (and copy'n'pasted from another scenario). The "trivial fix" (that would eliminate this exception) would be to eliminate the invokeAndWait methods, but that will have a negative impact if this code is invoked off the EDT as well -- the two situations much be handled differently. Take some time to determine when/where this code will run, and why.
As others have pointed out, this code seems confused: if it's off the EDT, manipulating Swing objects is bad, and if it's on the EDT then there is no need to invokeAndWait and blocking is bad.
Happy coding.
if that is eventually called from a event handler then it is called from the EDT (all your code will be unless you use swingworkers or explicitly create thread/use threadpools)
check the stack trace to find were it comes from
to fix it use aforementioned SwingWorker and override doInBackground() and you can check whether you are in the dispatch thread with SwingUtilities.isEventDispatchThread()
1) theMsg look like crazy theMsg = "someString" + localVariable + "anotherString"
2a) why did you call Swing GUI inside Basic File I/O
2b) why did you build GUI inside Basic File I/O
read File, close(); I/O Stream in finally block
3) you create lots of DoShowDialog(null, theMsg, 0));, every loop create one, and etc
4) every true and false move outside this I/O Stream
5) load every events to the some of Array, if I/O Stream
6) you code probably freeze GUI, if exist
7) move all Stream to the BackGround Task
I am trying to program a game in which I have a Table class and each person sitting at the table is a separate thread. The game involves the people passing tokens around and then stopping when the party chime sounds.
how do i program the run() method so that once I start the person threads, they do not die and are alive until the end of the game
One solution that I tried was having a while (true) {} loop in the run() method but that increases my CPU utilization to around 60-70 percent. Is there a better method?
While yes, you need a loop (while is only one way, but it is simplest) you also need to put something inside the loop that waits for things to happen and responds to them. You're aiming to have something like this pseudocode:
loop {
event = WaitForEvent();
RespondToEvent(event);
} until done;
OK, that's the view from 40,000 feet (where everything looks like ants!) but it's still the core of what you want. Oh, and you also need something to fire off the first event that starts the game, obviously.
So, the key then becomes the definition of WaitForEvent(). The classic there is to use a queue to hold the events, and to make blocking reads from the queue so that things wait until something else puts an event in the queue. This is really a Concurrency-101 data-structure, but an ArrayBlockingQueue is already defined correctly and so is what I'd use in my first implementation. You'll probably want to hide its use inside a subclass of Thread, perhaps like this:
public abstract class EventHandlingThread<Event> extends Thread {
private ArrayBlockingQueue<Event> queue = new ArrayBlockingQueue<Event>();
private boolean done;
protected abstract void respondToEvent(Event event);
public final void postEvent(Event event) throws InterruptedException {
queue.put(event);
}
protected final void done() {
done = true;
}
public final void run() {
try {
while (!done) {
respondToEvent(queue.take());
}
} catch (InterruptedException e) {
// Maybe log this, maybe not...
} catch (RuntimeException e) {
// Probably should log this!
}
}
}
Subclass that for each of your tasks and you should be able to get going nicely. The postEvent() method is called by other threads to send messages in, and you call done() on yourself when you've decided enough is enough. You should also make sure that you've always got some event that can be sent in which terminates things so that you can quit the gameā¦
I would look into Locks and Conditions. This way you can write code that waits for a certain condition to happen. This won't take a lot of CPU power and is even much more efficient and better performing than sleeping .
To make a thread run for an infinite time:
final Object obj = new Object();
try {
Thread th = new Thread(new Runnable() {
public void run() {
synchronized(obj) {
try {
System.out.println("Waiting");
obj.wait();
System.out.println("Done waiting");
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
});
th.start();
System.out.println("Waiting to join.");
// Dont notify; but wait for joining. This will ensure that main thread is running always.
th.join();
System.out.println("End of the Program");
} catch(Exception ex) {
ex.printStackTrace();
}
You may add Thread.sleep() with appropriate time to minimize useless loop iterations.
Another solution is using synchronization. While threads are not required to do anything, they enter into a sleeping state on a monitor using the wait() method, and then when the turn comes, required thread is woken up by the notify() method.
Actor model seems suitable for this scenario. Each person sitting on the table and the table itself can be modelled as actors and the event of passing the tokens and starting and stopping of the game can be modelled as messages to be passed between the actors.
As a bonus, by modelling the scenario as actors you get rid of explicit manipulation of threads, synchronization and locking.
On JVM I will prefer using Scala for modelling actors. For Java you can use libraries like Kilim. See this post for a comparison of Actor model related libraries in Java.
One Way is to use while loop but keep a check i.e
while(true){
if(condition!=true){
Thread.sleep(time);
}else{
break;
}
}
This way if your condition says game is not over it will keep person thread at sleep and memory consumption will be very low.
You should test for a condition in the while loop:
while (!gameOver)
{
do_intersting_stuff();
}
Heavy CPU load is typical for busy wait. Is your loop actually just checking a flag over and over, like
while (!gameOver)
{
if (actionNeeded)
{
do_something();
}
}
you might change to another notification system to sleep and wake up, as this just burns CPU time for nothing.