Is There a 'Block Until Condition Becomes True' Function in Java

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



Leave a reply



Submit