is there a 'block until condition becomes true' function in java?
Polling like this is definitely the least preferred solution.
I assume that you have another thread that will do something to make the condition true. There are several ways to synchronize threads. The easiest one in your case would be a notification via an Object:
Main thread:
synchronized(syncObject) {
try {
// Calling wait() will block this thread until another thread
// calls notify() on the object.
syncObject.wait();
} catch (InterruptedException e) {
// Happens if someone interrupts your thread.
}
}
Other thread:
// Do something
// If the condition is true, do the following:
synchronized(syncObject) {
syncObject.notify();
}
syncObject
itself can be a simple Object
.
There are many other ways of inter-thread communication, but which one to use depends on what precisely you're doing.
Wait Until Condition become true
Here is a little example of a main thread (think of it as your TCPClient) that waits until user clicks button (think of this part as your TCPProtocol):
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
public class Test extends JFrame {
public Object lock = new Object();
private JTextArea area = new JTextArea();
public Test() {
super("test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton send = new JButton("send");
send.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
synchronized (lock) {
lock.notify();
}
}
});
add(area);
add(send, BorderLayout.SOUTH);
}
public String pullText() {
String result = area.getText();
area.setText("");
return result;
}
public static void main(String[] args) {
Test t = new Test();
t.setSize(200, 200);
t.setVisible(true);
while (true) {
synchronized (t.lock) {
try {
t.lock.wait();
System.out.println(t.pullText());
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Maybe you can apply a similar approach to your system.
Warning: this is just a quick and dirty example to give you the idea, please double check it. In general you should be very careful when dealing with synchronization.
EDIT:
As a starting point you can modify your TCPProtocol class (the part you posted) like this:
public volatile boolean getPressed;
private Object lock = new Object(); // added lock for wait/notify coordination
private String Data; //changed scope to make it accessible in getMessage()
Jsend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
synchronized(lock){
Data = Jusertxt.getText(); // no more a local variable, it's an instance attribute now, see declaration above
Jusertxt.setText(null);
System.out.println(Data);
getPressed=true;
lock.notify(); // notify client that user performed action
}
});
}
public boolean getPressed(){
synchronized (lock) {
try {
lock.wait(); // wait for user to perform action...
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
return getPressed; // ...then return value (I guess getPressed will always be true at this point)
}
public String getMessage(){ // call this in TCPClient instead of pro.Jusertxt.getText()
return Data;
}
I added a lock object to enable wait/notify mechanism and applied that to your actionPerformed and getPressed methods.
I also changed the scope of Data variable and I added a public method to get its value (getMessage()). If you doublecheck your code you'll see that you will always get null from pro.Jusertxt.getText() in TCPClient.java because you set it to null in actionPerformed. So change pro.Jusertxt.getText() to pro.getMessage() in TCPClient.java.
// [...]
fromUser = pro.getMessage(); // used to be fromUser = pro.Jusertxt.getText();
// [...]
If you get this raw version to work then you can refine and refactor it to make it more clean and consistent. (for instance, I suspect you don't actually need getPressed variable as it's actually always true)
I confess I didn't test this code so you might have to fix or adjust it a little, but I hope it can clarify how I meant you could apply the code I posted to your system.
Hope it helps.
Good luck :-)
Using a wait block to make agents wait until condition is true
what you did is correct, but you have something missing.
Additionally to that, you need to do something like this in the resourcePool onrelease action
if(wait.size()>0)
wait.free(wait.get(0));
Then whenever a resource gets idle, you can release an agent from that wait block, if any exist there
Wait x milliseconds or until a condition becomes true
To be able to check that in Java 7 you need to write a callable.
@Test
public void send() {
//when
boolean sent = sendAsync(address, records, socket, true);
//then
if (sent) {
await().until(receivedPackageCount(), equalTo(false));
}
}
private Callable receivedPackageCount(String address) {
return new Callable() {
@Override
public boolean call() throws Exception {
return acknowledgementCache.asMap().containsKey(address);
}
};
}
It must be something similar above. There can be compilation errors because I wrote it without ide.
Wait until boolean value changes it state
This is not my prefered way to do this, cause of massive CPU consumption.
If that is actually your working code, then just keep it like that. Checking a boolean once a second causes NO measurable CPU load. None whatsoever.
The real problem is that the thread that checks the value may not see a change that has happened for an arbitrarily long time due to caching. To ensure that the value is always synchronized between threads, you need to put the volatile keyword in the variable definition, i.e.
private volatile boolean value;
Note that putting the access in a synchronized
block, such as when using the notification-based solution described in other answers, will have the same effect.
How do you pause a thread until a condition becomes true without busy waiting?
The underlaying problem is that you use a getter method to aquire an information and act on it. The principle which is violated here is Tell, don't ask!.
The OO whay to solve this is to introduce an interface (e.g.: PlayerMovingListener
).
The player class would hold an instance of an object implementing that interface (or a list of them). As soon as the player starts walking it calls the isMoving()
method defined in the interface implemented by the (or all) listener object(s) held by the player.
Most likely is triggered by a setter method in your current Payer
implementation.
Related Topics
In Java, Is It More Efficient to Use Byte or Short Instead of Int and Float Instead of Double
Case Insensitive String as Hashmap Key
Format File Size as Mb, Gb, etc
Preserving Parameter/Argument Names in Compiled Java Classes
Why Can't a Generic Type Parameter Have a Lower Bound in Java
How to Determine If a Date Is Between Two Dates in Java
Make Arraylist.Toarray() Return More Specific Types
Java Linkedhashmap Get First or Last Entry
Connecting an Input Stream to an Outputstream
Java Enum and Additional Class Files
Java 8 Streams Flatmap Method Example
Java Properties Utf-8 Encoding in Eclipse