Edit: a user marked that my question is a possible duplicate of this question: "What is the volatile keyword useful for", whose title is "What is the volatile keyword useful for?". I read the question but I don't see how it relates to my question.
Here is a program written in two .java files.
My question involves the if..else.. in the main method.
Note in the code below, the single line within the else {..} is commented out. I'll call this "version 1" of the program, and I'll call the program with that line commented back in "version 2".
// -------------
// The code below is in IfElseBugProgram.java
public class IfElseBugProgram {
public static void main(String[] args) {
MyJFrame terminal = new MyJFrame();
while (true) {
String keyReleased = terminal.getKeyReleased();
if (! keyReleased.equals("") )
{
System.out.print("#" + keyReleased);
}
else
{
// System.out.print("!" + keyReleased);
}
}
}
}
// -----
//The code below is in file MyJFrame.java
import javax.swing.JFrame;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
public class MyJFrame extends JFrame implements KeyListener
{
private List<KeyEvent> keyEventQueue;
public MyJFrame()
{
keyEventQueue = new ArrayList<KeyEvent>();
this.addKeyListener(this);
pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public void keyPressed(KeyEvent e)
{
}
public void keyTyped(KeyEvent e)
{
}
public void keyReleased(KeyEvent keyEvent)
{
keyEventQueue.add(keyEvent);
System.out.println("some key was released!" + keyEventQueue.size());
}
public String getKeyReleased()
{
int i = keyEventQueue.size();
if (i == 0)
{
return ("");
}
else
{
return ("" + i);
}
}
}
I expect that the code in the if {...} to be run, once I press a key on my keyboard. That is, I expect the
System.out.print("#" + keyReleased);
code to be run as soon as I press a key.
With version 1, I never seem to get System.out.print("#" + keyReleased); to be run; there are never "#1" or "#2" or "#3"s etc printed in the console.
With version 2 (that is, with the code in the else {..} block commented back in),
what USUALLY happens is that the print statement that prints out "!" gets run repeatedly, until I press a key. At that point, things like "#1" or "#2" etc get repeatedly printed.
what SOMETIMES happens is that I get no "!" nor "#1" or "#2" printed out! (With the same source code!)
Question: Why does the System.out.print("#" + keyReleased); line in the if {..} block not run in version 1, but (usually) does in version 2?
Additional Observations:
The print statement System.out.println("some key was released!" + keyEventQueue.size()); in MyJFrame#keyReleased() always prints out, no matter how I change the code.
I thought that perhaps something might be wrong with my console in Netbeans. But I tried running other code in the if {..} block, such as the line of code java.awt.Toolkit.getDefaultToolkit().beep();, which makes a sound. I also tried making some graphics display in the JFrame itself. The result is the same: with the line of code in the else {...} commented out, the code in the if {..} block doesn't seem to run; but if I comment the line of code in the else {..} back in, the code in the if {...} block (including making a sound or displaying something in the JFrame) does in fact run.
I'm pretty sure that the condition of the if, if (! keyReleased.equals("") ) is correct. I tried adding the one line of code System.out.println("?" + (! keyReleased.equals("")) ); just above the if (! keyReleased.equals("") ), and consistently on my console I would get "?false" printed repeatedly, until I pressed a key, at which point I got "?true" printed repeatedly. But also: weirdly, putting in this one line of code (System.out.println("?" + (! keyReleased.equals("")) );) above the if in version 1 causes the lines of code in the if {..} block to now run?!
(optional) Background:
This section explains the code I am ultimately trying to write. If you wish to suggest an approach that might get me to this goal, that is different than the approach I'm using above, please feel free to suggest it.
I am trying to build a simple class called MyJFrame which can help motivate a friend learn how to program. The idea is to allow him to learn about variables in a visually motivated way, by programming extremely simple games, just like I learned when learning BASIC as a child. I want him to be able to write a program, completely contained in one main() method; I want him to have a simple way to draw a string on the screen, and a simple way to get user input. An example program might look like this:
int playerLocationX = 3;
int playerLocationY = 4;
MyJFrame terminal = new MyJFrame();
while(true)
{
// erase player that was drawn during the previous iteration of this loop
terminal.write(" ", playerLocationX, playerLocationY);
// get a key the user last pressed (if the user pressed a key) and update
// player location
String keyReleased = terminal.getKeyReleased();
if (keyReleased.equals("LEFT"))
{
playerLocationX = playerLocationX - 1;
}
else if (keyReleased.equals("RIGHT"))
{
playerLocationY = playerLocationY + 1;
}
// draw player again, using most recent player location
terminal.write("#", playerLocationX, playerLocationY);
}
I don't want to have him need to write his own keyReleased() method (ie, implementing a KeyListener interface), because this requires knowledge of writing your own methods; it also requires knowledge of objects, because a keyReleased() method has no way of modifying the local variables playerLocationX and playerLocationY stored in main().
The Java VM is allowed to optimize consecutive, unsynchronized loads by assuming that a variable will not be modified by concurrent threads.
If you want a spin loop over a field that is going to be changed by another thread, you can have the VM make sure every read sees the latest changes by marking it as volatile:
private volatile List<KeyEvent> keyEventQueue;
As the JLS puts it:
A write to a volatile field (ยง8.3.1.4) happens-before every subsequent read of that field.
I don't know whether your V2 is guaranteed to work according to the JLS, but the System.out PrintStream will synchronize on every write, restricting the optimizations that the VM is allowed to do.
The main reason you are experiencing such unpredictable behavior is because you actually created a multi-threaded program where you are accessing Swing components from a thread other than the event dispatching thread.
Specifically the line:
MyJFrame terminal = new MyJFrame();
starts the Swing event dispatching thread but the line (for example):
String keyReleased = terminal.getKeyReleased();
accesses the terminal (a Swing component) from the main thread.
From the Swing package documentation:
In general Swing is not thread safe. All Swing components and related classes, unless otherwise documented, must be accessed on the event dispatching thread.
Before moving ahead on trying to get this code to work, I would suggest going through the tutorial Lesson: Concurrency in Swing.
Related
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
.
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.
I have this code sample
public static class BlinkMe extends Thread {
int counter = 0;
protected boolean stop = true;
public void run() {
while (stop) {
counter++;
if (counter % 2 == 0) {
jLabel4.setVisible(true);
jLabel7.setVisible(true);
jLabel8.setVisible(true);
counter = 0;
} else {
jLabel4.setVisible(false);
jLabel7.setVisible(false);
jLabel8.setVisible(false);
if (jButton4.isEnabled() == false) {
stop = false;
jLabel4.setVisible(true);
jLabel7.setVisible(true);
jLabel8.setVisible(true);
if (jButton2.isEnabled() == false) {
stop = true;
jButton2.setEnabled(false);
}
}
}
}
}
}
I need to stop this Thread when I press my Stop Button...
Here's the code I'm using for the Button's function but it is not working. ***The Thread is not working at ll*
Here is the Button's function
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
BlinkMe b=new BlinkMe();
b.stop(); //here I have even used b.interrupt(); but doesn't stop the
}
There are many, many things wrong in this code.
you're accessing Swing components from a background thread. That's forbidden. Only the event dispatch thread is allowed to access Swing components
You're trying to stop() a thread, although this method is deprecaed and should never, ever be used, as the documentation explains
Instead of stopping the actual thread, you create a new instance of that thread class, and call stop() on that new instance.
You "blink" without any delay between the blink.
Your thread uses a stop variable, but this variable is never modified anywhere. Even if it was, it's not volatile, so you have a big chance of not seeing the modification, and thus not stopping the thread.
Read the Swing tutorial abount concurrency. And use a Swing Timer, which is designed to do that kind of thing, safely.
You are creating a new thread in actionPerformed and trying to stop the same, which was not started so far. Try calling stop in actual thread.
The initial value of your stop is "true". This means that when the thread starts, the run method executes but will not execute the while block because the condition will result to false right away.
First, you need to change your while loop into like this:
while(!stop) { /* the rest of your code */ }
Next, you need to create a method in your BlinkMe thread that would allow other objects in your program that would make it stop. The method would look something like this:
public void stopBlinking() {
stop = true;
}
Calling the above method will stop the infinite loop in the run method.
I don't think you will see a blinking effect when you run your program. It is because the loop executes very fast. I suggest you put a Thread.sleep(1000) somewhere in the loop so that there is time to reflect the blink effect visually.
EDIT: Ok, this is really stupid but I don't know why I didn't see it was a normal loop without the usual increments. I hope I was drunk when I posted this question because now I feel super idiot. Thanks anyway guys!
I'm following some tutorials on Java multi-threading in order to gather as much information and examples as possible.
On the Oracle website there is an official tutorial on Java Concurrency and I am looking at the Guarded Blocks section (here).
Whereas all the concepts are clear, I am reading the Producer/Consumer example at the bottom of the page and I do not understand some parts of the code.
Specifically, in the following is the code for the run() method of the Consumer class, where I do not understand how that for loop is supposed to work. It doesn't even look as it can work to me.
Can anyone explain me?
public void run() {
Random random = new Random();
for (String message = drop.take();
! message.equals("DONE");
message = drop.take()) {
System.out.format("MESSAGE RECEIVED: %s%n", message);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
}
}
It's just for loop being used in a non-idiomatic way.
You have the initialization String message = drop.take(); (instead of int i = 0;).
Then you have the test !message.equals("DONE"); (instead of i < 10).
Finally you have the "increment" or loop-advance or whatever the actual term is. Get the next value with message = drop.take(); (instead of i++).
Maybe it would be easier to understand when converted to a while-loop:
public void run() {
Random random = new Random();
String message = drop.take()
while (!message.equals("DONE")) {
System.out.format("MESSAGE RECEIVED: %s%n", message);
try {
Thread.sleep(random.nextInt(5000));
} catch (InterruptedException e) {}
message = drop.take()
}
}
Keep in mind that the for-loop generally consists of three parts:
for (INITIALIZATION; CONDITION; AFTERTHOUGHT)
{
// Code for the for-loop's body goes here.
}
INITIALIZATION is run once before the first iteration, CONDITION is checked prior to every iteration and AFTERTHOUGHT is executed after every iteration.
(Taken from https://en.wikipedia.org/wiki/For_loop#Traditional_for-loops)
So in this example, the INITIALIZATION of the for-loop creates the message variable and takes the first message from drop. It then checks it in the CONDITION block to see if its is anything but DONE. If it is, the loop body is executed once, printing the message and sleeping for up to 5000 milliseconds. Then the next message is taken in the AFTERTHOUGHT clause and the loops checks the CONDITION block again to either print the next message or leave the loop once it receives DONE.
I have the following Java program:
public class A extends Thread {
int count;
#Override
public void run() {
while (true)
count++;
}
public static void main(String...strings){
A obj = new A();
obj.start();
System.out.println("The value of count is " + obj.count);
}
}
When running this program the output is: The value of count is 0 (and the program stays running). As far as my understanding with thread it should run in an infinite loop and never print 0. Could anyone help me understanding the nature of this program.
The thread starts at about the same time as the System.out.println runs, and since the thread is background, the println does not wait for it to run, and so you are seeing the initial value of count.
Also as an aside, the count variable should be declared volatile to ensure that the main thread sees changes to the variable made in the loop thread.
The "thread" isn't doing the print, your main is. What were you expecting to happen?
You should also use some kind of protection so both threads can safely access the variable.
Wouldn't the System.out call only run once?
I would put the System.out.println call inside the while loop.
Its probably better to use a getter/setter method for count and make sure only one or the other can access the variable at any given time.