I've created a java code (swing GUI JFrame form) that call another class function (which is in another project) when the button is pressed, but it needs me to click the button twice in order to successfully return the value from the called function. Is there any solution?
here is my code,
The GUI
package aarib;
import java.awt.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import AlKhalil.ui.Aarib;
public class GUI extends javax.swing.JFrame {
public String Input;
public String Lexems;
public Aarib A;
public GUI() {
initComponents();
A = new Aarib();
jTextField1.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
jLabel2.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
if(jTextField1.getText().isEmpty())
{
jLabel2.setText("No input");
}
else{
Input = jTextField1.getText().toString();
A.inputText= Input;
try {
Lexems = A.LexicalAnalysis();
jLabel2.setText(Lexems);
} catch (Exception ex) {
jLabel2.setText("Error");
Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
and the remote function
package AlKhalil.ui;
import java.util.*;
import java.util.List;
import AlKhalil.token.*;
import AlKhalil.analyse.*;
import AlKhalil.*;
import AlKhalil.result.*;
public class Aarib {
public Analyzer analyzer;
public String myResult="";
public String inputText="";
public Aarib() {
Settings settings = new Settings();
analyzer = new Analyzer();
}
public String LexicalAnalysis() throws Exception {
Thread t = new Thread()
{
public void run()
{
//some code
...
...
...
}
};
t.start();
return myResult;
}
}
Thanks in advance :)
The solution is to wait for the result produced in the Thread t. With your current code you start a concurrent thread and instantly return the attribute myResult. With the second click on your button the myResult is (most times) filled by the thread and returned after starting another concurrent thread doing the calculation.
I suggest considering some kind of Observer-Pattern for your program. Your GUI then should obsever the calculating thread and get notified about a result, which then will be handled.
But as we all cannot see the code executed in the thread and as you wait for the thread to finish, why not simply not use a thread.
Related
I am working on a college course project, a JavaFX application that is simulating a garage with vehicles moving around. Following on this answer, I created a mechanism for constantnly refreshing GUI without flooding the JavaFX thread.
The entire code can be found here.
Observer is a daemon thread whose task is computing a String value for output and sending it it to a TextArea, which is constantly being updated.
Observer run method:
#Override
public void run() {
while (true) {
synchronized (Garage.getLock()) {
try {
// buffer = new StringBuffer("");
buffer.append('\n');
garage.print(buffer);
buffer.append('\n');
garage.outputText.set(buffer.toString());
System.out.println(buffer.toString());
Garage.getLock().wait(3000);
} catch (InterruptedException exception) {
exception.printStackTrace();
} finally {
Garage.getLock().notifyAll();
}
}
}
}
Observer object has a reference to the model class - garage. print() method of the Garage class basically appends stuff to the buffer.
The complete output is printed to the console, which works fine. The output is also used to set outputText, a SimpleStringProperty, which has a listener attached in the MainControllerClass.
outputText member:
public class Garage implements Externalizable {
...
public SimpleStringProperty outputText = new SimpleStringProperty();
...
}
Refreshing the GUI is initiated with a button click.
MainController class:
package garage.controller;
import java.util.concurrent.atomic.AtomicInteger;
import garage.model.*;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.stage.Stage;
public class MainController {
#FXML
private TextArea output;
#FXML
private Button startButton;
private Garage model;
public MainController() {
}
private AtomicInteger control = new AtomicInteger(-1);
#FXML
public void initialize() {
}
#FXML
private void handleStartButton() {
model.outputText.addListener(new ChangeListener<String>() {
#Override
public void changed(final ObservableValue<? extends String> observable, final String oldValue,
final String newValue) {
if (control.getAndSet(1) == -1) {
javafx.application.Platform.runLater(new Runnable() {
#Override
public void run() {
control.set(-1);
output.setText(newValue);
}
});
}
}
});
}
public void setModel(Garage model) {
this.model = model;
}
}
When I run the application and click the button, everything is going well. TextArea is updated in real time. Since the output is constantly being appended to the StringBuffer, I wanted to refresh it in every cycle and get something like a simulation.
This is where the problems start.
When I uncomment the line in the Observer run method
// buffer = new StringBuffer("");
nothing is being printed to the TextArea. The console output is working well.
I also tried with other StringBuffer methods like delete and setLenght but nothing seems to work. However I try to clean the buffer, TextArea is no longer updated.
I cannot seem to reset the StringBuffer.
What am I missing here?
EDIT: print() methods
Garage print method
public void print(StringBuffer buffer) {
synchronized (Garage.lock) {
synchronized (lock) {
for (int i = 0; i < platformCount; i++)
platforms.get(i).print(buffer);
}
}
}
GarageItem print method
package garage.model;
import java.io.*;
public interface GarageItem extends Serializable {
public void print(StringBuffer buffer);
}
Lane print method
package garage.model;
public class Lane implements GarageItem {
private static final long serialVersionUID = 5L;
#Override
public void print(StringBuffer buffer) {
synchronized (Garage.getLock()) {
buffer.append('.');
}
}
}
ParkingSpot print method
package garage.model;
public class ParkingSpot implements GarageItem {
private static final long serialVersionUID = 4L;
#Override
public void print(StringBuffer buffer) {
synchronized (Garage.getLock()) {
buffer.append('*');
}
}
}
Vehicle print method
#Override
public void print(StringBuffer buffer) {
synchronized (Garage.getLock()) {
buffer.append(symbol);
}
}
where symbol is 'V'.
Found the answer today. My text example was trivial and by the time I clicked the handleStartButton, all of the cars have finished moving and parked in the garage.
Because I reset the buffer in every loop iteration, it meant that the state of the garage didn't change anymore and it's String representation was the same. Because of this, change listener was not triggered and nothing was printed out to the TextArea.
I have to change a Boolean variable in application thread(setReadyToUpload) and hearing this change(isReadyToUpload) another thread (server thread) will do something.Though server thread is in a while loop and checking all he time it is not catching the change when i change the Boolean variable in application thread.
Application thread
package server;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressIndicator;
import javafx.stage.FileChooser;
import java.io.File;
public class serverController {
serverMain main;
#FXML
private Button upload;
#FXML
private ProgressIndicator indicator;
#FXML
void pressed(ActionEvent event) {
FileChooser fc=new FileChooser();
File file=fc.showOpenDialog(main.getStage());
if(file!=null) {
main.setFileLoaction(file.getAbsolutePath());
System.out.println("it is done");
main.setReadyToUpload(true);
}
else
{
Alert alert=new Alert(Alert.AlertType.ERROR);
alert.setHeaderText("Upload problem");
alert.setContentText("You have'nt select any file to upload");
alert.showAndWait();
}
}
public void setMain(serverMain main) {
this.main = main;
}
}
server thread
package tcpobject;
import java.io.File;
import java.util.*;
import server.serverMain;
import util.NetworkUtil;
public class WriteThreadServer implements Runnable {
private Thread thr;
private NetworkUtil nc;
private serverMain main;
private LargeFile o;
private LargeFileInserter lfi;
String name;
public WriteThreadServer(NetworkUtil nc,String name, serverMain main) {
this.nc = nc;
this.name=name;
this.thr = new Thread(this);
this.main=main;
thr.start();
}
public void run() {
while(true)
{
try {
//System.out.println("it is "+main.isReadyToUpload());
// if i print this then thelower block works good but if i dont it cant catch the change
System.out.println("it is checking");
if(main.isReadyToUpload())
{
System.out.println("it is ru");
FileDataHandler();
}
if(main.isStartUpload()) {
//System.out.println("it is su");
LargeFileHandler();
System.out.println("it is su");
for (int i = 0; lfi.hasMoreBytes(); i++) {
o = lfi.nextByte();
nc.write(o);
}
lfi.close();
}
} catch(Exception e) {
System.out.println (e+" here");
e.printStackTrace();
nc.closeConnection();
}
}
}
void FileDataHandler ()
{
FileDataMessage fd=new FileDataMessage(main.getFileLoaction());
nc.write(fd);
main.setReadyToUpload(false);
}
void LargeFileHandler ()
{
try {
lfi=new LargeFileInserter(main.getFileLoaction());
} catch (Exception e) {
e.printStackTrace();
}
//FileDataMessage fd=new FileDataMessage("F:\\L-2 T-1\\EEE 263\\Electronic devices and ckt theory- boylestad 11th edition.pdf");
//System.out.println(fd);
//System.out.println(fd.sizetoPrint());
LargeFile o;
main.setStartUpload(false);
}
}
All the function and variable is written in main class and both thread have access to that class.
Without having the rest of the code available, methods setReadyToUpload and isReadyToUpload have issues with visibility of shared object, which is flag you are setting to true.
What could happen is that two threads run on different cores, and one thread updates the flag to true. This update could happen within CPU cache which is not readable by the another thread checking for the value as long the change is not flushed back into main memory.
You could fix current design by :
a) having the flag volatile which will force updates of cache lines between CPU registers
b) make methods synchronized, with the same effect as above
What you should do instead however, would be to use wait and notify instead of busy waiting in the server thread and wasting the CPU cycles.
Simply create monitor variable such as:
private final Object monitor = new Object();
and in the server code do:
synchronized(monitor) {
monitor.wait():
}
so when the change is ready you could notify change from another thread like this:
synchronized(monitor)
{
monitor.notify();
}
Server could implement Observer while your client is Subject. This would let you simply notify the changes via Observer's interface method update.
Note that in theory wait could be interrupted, and therefore you should check if the condition is met upon wake up, and if not continue waiting.
This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
(1 answer)
Closed 7 years ago.
i've been making a countdown program, and i came up with this.
package main;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class Gatoo extends JFrame implements ActionListener {
private int sec, min, secTot, since = 999;
private long lastTime;
private JTextField mm = new JTextField(2), ss = new JTextField(2);
private JLabel minLab = new JLabel("Minutes:"), secLab = new JLabel(
"Seconds:");
private JButton start = new JButton("Start");
private Clip done;
private boolean started = false;
private static final long serialVersionUID = 4277921337939922028L;
public static void main(String[] args) {
Gatoo cake = new Gatoo("Title");
cake.pack();
cake.setSize(800, 600);
cake.setLocationRelativeTo(null);
cake.setDefaultCloseOperation(3);
cake.setVisible(true);
cake.run();
}
public Gatoo(String s) {
super(s);
setLayout(new FlowLayout());
start.addActionListener(this);
add(minLab);
add(mm);
add(secLab);
add(ss);
add(start);
}
#Override
public void actionPerformed(ActionEvent e) {
started = true;
}
public void play(File file) throws MalformedURLException,
UnsupportedAudioFileException, IOException,
LineUnavailableException {
AudioInputStream ais = AudioSystem.getAudioInputStream(new File(
"lib/done.wav"));
DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
done = (Clip) AudioSystem.getLine(info);
done.open(ais);
done.start();
}
public void run() {
while (true) {
System.out.print("");// needed?
if (started) {
try {
min = Integer.parseInt(mm.getText());
sec = Integer.parseInt(ss.getText());
secTot = (min * 60) + sec;
lastTime = System.currentTimeMillis();
while (secTot > 0) {
since = (int) (System.currentTimeMillis() - lastTime);
if (since > 998) {
lastTime = System.currentTimeMillis();
secTot--;
}
}
play(new File("done.wav"));
} catch (NumberFormatException exception) {
System.out.println("Minutes and seconds must be numbers.");
return;
} catch (Exception exception) {
exception.printStackTrace();
}
started = false;
}
}
}
}
In the while loop at the end the countdown code doesn't execute without a print / println statement inside. How come? The program works perfectly fine with the print statement though.
First and foremost, your program is thread-unsafe because boolean started is a shared variable, but it is neither volatile nor accessed within synchronized blocks.
Now, accidentally, PrintStream#print is a synchronized method and, on any actual architecture, entering and exiting a synchronized block is implemented using memory barrier CPU instructions, which cause a complete synchronization between the thread-local state and main memory.
Therefore, by pure accident, adding the print call allows the setting of started flag by one thread (the EDT) to be visible by another (the main thread).
You have poor design for Swing application.
Don't use while(true) loop in your run() method. Read more about Concurency in Swing.
Call events with help of Listeners(ActionListener e.g.) instead of flags(started here).
Instead of counting time use Swing Timer.
Change your run() method like next:
public void run() {
min = Integer.parseInt(mm.getText());
sec = Integer.parseInt(ss.getText());
secTot = (min * 60) + sec;
Timer timer = new Timer(1000*secTot, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
play(new File("done.wav"));
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
timer.start();
}
actionPerformed() method :
#Override
public void actionPerformed(ActionEvent e) {
run();
}
and remove cake.run() in main method.
Look, I made a SSCCE reproducing this behavior. It is a really good question.
public class ThreadRacing implements Runnable
{
public boolean started = false;
public static void main(String[] args)
{
new ThreadRacing().test();
}
public void test()
{
new Thread(this).start();
try
{
Thread.sleep(1000);
} catch (Exception e)
{
}
started = true;
System.out.println("I did my job");
}
#Override
public void run()
{
while (true)
{
//System.out.print("");
if (started)
{
System.out.println("I started!!");
}
}
}
}
This prints: "I did my job". Nothing more. Adding a volatile keyword actually fixes the problem.
To me, it looks like the second Thread gets not notified about the update to started because he is too bussy.
I would surmise that your busy-wait loop is hogging the CPU so severely it is unable to do anything. The print statement is causing just enough of a thread context switch that it is able to get other work done.
Edit: Okay, I did a little testing. I was able to reproduce OP's problem on the HotSpot Server VM. Using Thread.currentThread().setPriority(Thread.MIN_PRIORITY); did not fix it, so it is not a starvation issue. Setting the variable to volatile as #MartinCourteau, #MarkoTopolnik suggested, did fix it. That makes sense. I couldn't originally reproduce the problem on the HotSpot Client VM; apparently its optimizations are too weak for it to cache the started variable.
(Still, if the Java audio thread had a lower than normal thread priority and it were a single-CPU system, starvation was a plausible hypothesis.)
I am sorry that this is too long, and it may seem as too much asking, but If you can figure out what is wrong at a glance, please let me know.
In this program I try to input some words (phrase) from the keyboard every time taking one token and assign it to an object sharedStorer (then print the assigned value to keep track of what is input as I have a chain of words to input separately). This is done by one thread (Thread of class Retriever which implements Runnable)
There is another thread of class TokenReader that reads the value of sharedStorer and print it out. TokenReader waits for Retriever for input and when Retriever tries to input while TokenReader has not yet read the previous token Retriever waits.
The question I have is that at the end TokenReader waits forever for Retriever which has completed its task, and so the program never terminates.
Here is all 4 classes (and 1 Interface) I am using to perform the desired task.
package Multithreads;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExerciseTest {
public static void main(String[] args) {
ExecutorService app=Executors.newFixedThreadPool(2);
Storer st=new SyncStorer();
System.out.println("Operation performed\t\t Value");
try{
app.execute(new Retriever(st));
app.execute(new TokenReader(st));
}catch(Exception e){
e.printStackTrace();
}
app.shutdown();
}
}
package Multithreads;
public interface Storer {
public void set(String token);
public String get();
}
package Multithreads;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Scanner;
import java.util.StringTokenizer;
public class Retriever implements Runnable {
private Scanner scanner;
private String token;
private String currentToken;
private Storer sharedStorer;
private Random rd=new Random();
public int tokenLength=0;
public Retriever(Storer st) {
sharedStorer=st;
}
public Retriever() {
}
#Override
public void run() {
System.out.println("Enter a phrase");
scanner = new Scanner(System.in);
token=scanner.nextLine();
StringTokenizer tokenizer=new StringTokenizer(token);
while(tokenizer.hasMoreTokens())
{
tokenLength++;
currentToken=tokenizer.nextToken();
try{
Thread.sleep(10*rd.nextInt(2000));
sharedStorer.set(currentToken);
}catch(NoSuchElementException e){
e.printStackTrace();
}catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("Done Inputting The phrase");
}
}
package Multithreads;
import java.util.Random;
public class TokenReader implements Runnable {
private Random rd=new Random();
private Storer sharedStorer;
Retriever rtr=new Retriever();
private int count=rtr.tokenLength;
public TokenReader(Storer st) {
sharedStorer=st;
}
#Override
public void run() {
String str="null";
int i=0;
try {
while(i <= count){
Thread.sleep(15*rd.nextInt(2000));
str=sharedStorer.get();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Consumer done reading");
}
}
package Multithreads;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SyncStorer implements Storer {
private Lock accessLock=new ReentrantLock();
private Condition canInput = accessLock.newCondition();
private Condition canRead = accessLock.newCondition();
private String string="null";
private boolean isEmpty=false;
#Override
public void set(String token) {
accessLock.lock();
try
{
while(isEmpty){
System.out.println("Retriever waiting");
canInput.await();
}
string=token;
isEmpty=true;
System.out.println("Retriever inputs\t\t "+string);
canRead.signal();
}catch(InterruptedException e){
e.printStackTrace();
}finally{
accessLock.unlock();
}
}
#Override
public String get() {
accessLock.lock();
try{
while(!isEmpty)
{
System.out.println("No token to read");
canRead.await();
}
isEmpty=false;
System.out.println("TokenReader reads\t\t "+string);
canInput.signal();
}catch(InterruptedException e)
{
e.printStackTrace();
}finally{
accessLock.unlock();
}
return string;
}
}
The problem that is causing the app to run forever is that this is an infinite loop:
while(i <= count){
Thread.sleep(15*rd.nextInt(2000));
str=sharedStorer.get();
}
because you are not decrementing i. And the interrupt-based mechanism you are trying to use to break out of the loop (via an exception!) is broken too.
The Thread.sleep(15*rd.nextInt(2000)) line looks like a hack so that you can get an InterruptedException when the task is interrupted, but:
the point of sleeping for a random number of milliseconds escapes me, and
it would be simpler to just call Thread.interrupted().
Besides, the approach isn't reliable anyway because there is a chance that the interrupt will happen after the point at which you are waiting / testing for it; i.e. in the get() call. And if that get() call is never going to return because the store is empty and the retriever has ended ... then you will wait "for ever".
There is one final problem. You need to call app.shutdownNow() if you want the executor service to interrupt the worker threads ...
If I was trying to implement this (using interrupts), I'd change it so that get and set didn't "gobble up" the interrupt. If they see the interrupt, they should either:
allow the InterruptedException to propagate (after relevant cleanup), or
set the thread's interrupted flag again in the exception handler.
I'm working on a J2ME Bluetooth application, and one of the classes searches for other Bluetooth devices. It does this in another thread, so the GUI doesn't freeze up.
The problem I have is how to pass messages to the thread. I can ask it to search, or cancel searching, and it can tell the GUI it has found some other devices. Currently I use notify and wait, but that seems like a hack. What I really want is some way of calling notify with a parameter, for example what I want it to do. Is there any way to do this?
The general approach to this kind of situation must be as follows:
Decouple the remote source of the data with the "View".
Make sure that the view is capable of updating dynamically when the underlying data changes. J2ME components do this by default - but if you author your own components, then you must take this into consideration.
Run a separate thread and retrieve data.
Notify the view whenever the data arrives.
The working code for the MIDlet is posted below
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.List;
import javax.microedition.midlet.*;
public class AsyncUI extends MIDlet implements SearchListener, CommandListener{
Command CANCEL = new Command("STOP SEARCH",Command.CANCEL,1);
Command EXIT = new Command("EXIT",Command.EXIT,2);
SearchDevices finder = new SearchDevices();
List deviceList = new List("List of Devices",List.IMPLICIT);
public void startApp() {
Display d = Display.getDisplay(this);
finder.setSearchListener(this);
deviceList.addCommand(CANCEL);
deviceList.addCommand(EXIT);
deviceList.setCommandListener(this);
d.setCurrent(deviceList);
new Thread( finder).start();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void found( Device d){
deviceList.append(d.getName(), null);
}
public void commandAction( Command c, Displayable d){
if( c == CANCEL){
finder.cancel();
deviceList.removeCommand(CANCEL);
}else if( c== EXIT ){
finder.cancel(); /* Cleanup all resources before you quit*/
notifyDestroyed();
}
}
}
class SearchDevices implements Runnable{
private boolean keepFinding=true;
private static final int LONG_TIME=10000; /* 10 Seconds */
SearchListener l =null; /* Currently only one listener. There could be many*/
public void run(){
int i =0;
System.out.println(" -- Started the activity of finding --");
while( keepFinding){
try {
Thread.currentThread().sleep(LONG_TIME);
Device d = new Device("Device Found "+i);
i++;
System.out.println(" -- Found the device --");
l.found(d);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.println(" -- No more devices will be found --");
}
public void cancel(){ keepFinding = false; }
public void setSearchListener( SearchListener l){this.l=l;}
}
class Device{
String name;
public Device(String name ){ this.name = name; }
public String getName(){ return name ; }
}
interface SearchListener{
public void found( Device device);
}
You'll have to implement you're own blocking queue, this is actually a producer-consumer problem. Once you have a blocking queue, you can then easily wrap pushes to the queue in their own methods, making it feel like you're doing asynchronous calls to the worker thread.