Though my actual problem is bit different , solving the following problem will help me . I have built a simple javafx application with scenebuilder . I would like to take input from user via a textField in my application and print that one in another class Say, class A. How can i make a thread, in class A, wait until my another guicontroller notify after getting value from user . I want to do this in a loop.
To be precise, How can i use wait and notify among threads in different classes ?
Please pardon me for my scrappy question . thnx in advance
Edited: My actual program is to build a chat messenger . Where i have a thread that will , after having the input from user , will forward to recipient . User will give input in a textField which will be handled in a guicontroller.
I want my guiController to notify the Thread that is waiting for sending message.
How can i do that ?
You could theoretically do it like this
@Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
List<String> messages = new LinkedList<>();
Thread thread = new Thread(() -> {
while (true) {
String message;
synchronized (messages) {
if (messages.isEmpty()) {
// empty message queue -> wait
try {
messages.wait();
} catch (InterruptedException ex) {
// unknown cause of interrupt -> just try reading the messages anew
continue;
}
}
message = messages.remove(0);
}
System.out.println("sending message: " + message);
try {
// simulate delay
Thread.sleep(3000);
} catch (InterruptedException ex) {
}
}
});
thread.setDaemon(true);
thread.start();
textField.setOnAction(evt -> {
synchronized (messages) {
// add new message to queue
messages.add(textField.getText());
// notify thread
messages.notify();
}
textField.clear();
});
Scene scene = new Scene(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
However there are much easier ways to achieve this effect:
BlockingQueue
This class is designed for this exact scenario: a consumer waiting for a producer, if necessary.
LinkedBlockingQueue<String> messages = new LinkedBlockingQueue<>();
Thread thread = new Thread(() -> {
while (true) {
String message;
try {
message = messages.take();
} catch (InterruptedException ex) {
continue;
}
System.out.println("sending message: "+message);
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
}
}
});
thread.setDaemon(true);
thread.start();
textField.setOnAction(evt -> {
try {
messages.put(textField.getText());
textField.clear();
} catch (InterruptedException ex) {
}
});
ExecutorService
This class simply allows you to post the task to send the info to a ExecutorService
that takes care of scheduling and executing the task. You can simply submit one task per message.
private ExecutorService executor;
@Override
public void init() throws Exception {
executor = Executors.newSingleThreadExecutor();
}
@Override
public void stop() throws Exception {
executor.shutdownNow();
// TODO: handle unsent messages or replace with executor.shutdown()
}
private void postMessage(String message) {
executor.submit(() -> {
System.out.println("sending message: "+message);
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
}
});
}
@Override
public void start(Stage primaryStage) {
TextField textField = new TextField();
textField.setOnAction(evt -> {
postMessage(textField.getText());
textField.clear();
});
Scene scene = new Scene(textField);
primaryStage.setScene(scene);
primaryStage.show();
}
Note that there are different executors available to adjust the scheduling and for using multiple threads.