As I said in title, I'm trying to make Producer-Consumer case with the usage of JavaFx. For the start I will show what the problem is:
Basically I got TabPane with three tabs:
- "Main Menu" with Buttons to "start production", "stop production" and two TextAreas each for showing results of producers-consumers work (there will be 2 for each branch)
- "First Producer" for typing producer name and slider for time of production (basically value for Thread.sleep(long m))
- "Second Producer" is exactly like the first So, now to the matter itself. After "accepting" data of both producers and starting production-consumption I got stuck on a problem with settingText to both TextAreas of producers and consumers. I tried binding them to tasks, but that didn't work out (maybe I did something wrong, I don't know).
Here is my code also:
Controller.java:
package com.example.case4javafx;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import java.net.URL;
import java.util.LinkedList;
import java.util.ResourceBundle;
public class Controller implements Initializable {
private LinkedList<String> listOfProducts = new LinkedList<>();
@FXML
private Slider sldFirstProd, sldSecondProd;
int mSldFirstProdValue, mSldSecondProdValue;
@FXML
private TextField txtFirstProd, txtSecondProd;
@FXML
private static TextArea txtProdInfo, txtConsInfo;
private String nameOfProd1, nameOfProd2;
private int timeOfProd1, timeOfProd2;
private Producer producer1, producer2;
private Consumer consumer1, consumer2;
@FXML
private Button btnStartProduction, btnStopProduction, btnFirstProdClear, btnFirstProdAccept, btnSecondProdClear, btnSecondProdAccept;
@FXML
private Label lblSldFirstProd, lblSldSecondProd;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
sldFirstProd.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observableValue, Number number, Number t1) {
mSldFirstProdValue = (int) sldFirstProd.getValue();
lblSldFirstProd.setText(mSldFirstProdValue + " ms");
}
});
sldSecondProd.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observableValue, Number number, Number t1) {
mSldSecondProdValue = (int) sldSecondProd.getValue();
lblSldSecondProd.setText(mSldSecondProdValue + " ms");
}
});
}
public void onStartProduction(ActionEvent e) throws InterruptedException {
if(btnFirstProdAccept.isDisabled() && btnSecondProdAccept.isDisabled()) {
producer1 = new Producer(listOfProducts, nameOfProd1, timeOfProd1);
Thread t1 = new Thread(producer1);
consumer1 = new Consumer(listOfProducts);
Thread t2 = new Thread(consumer1);
producer2 = new Producer(listOfProducts, nameOfProd1, timeOfProd1);
Thread t3 = new Thread(producer2);
consumer2 = new Consumer(listOfProducts);
Thread t4 = new Thread(consumer2);
t1.setDaemon(true);
t2.setDaemon(true);
t3.setDaemon(true);
t4.setDaemon(true);
t1.start();
t2.start();
t3.start();
t4.start();
btnStartProduction.setDisable(true);
}
}
public void onStopProduction(ActionEvent e) {
if(producer1 != null) {
producer1.cancel();
}
if(producer2 != null) {
producer2.cancel();
}
if(consumer1 != null) {
consumer1.cancel();
}
if(consumer2 != null) {
consumer2.cancel();
}
setEnableDisableProdData(txtFirstProd, sldFirstProd, true);
setEnableDisableProdData(txtSecondProd, sldSecondProd, true);
setEnableDisableProdButt(btnFirstProdClear, btnFirstProdAccept, true);
setEnableDisableProdButt(btnSecondProdClear, btnSecondProdAccept, true);
btnStartProduction.setDisable(false);
}
public void onClearFirstProducer(ActionEvent e) {
setClearProd(txtFirstProd, sldFirstProd, lblSldFirstProd);
}
public void onAcceptFirstProducer(ActionEvent e) {
nameOfProd1 = txtFirstProd.getText();
timeOfProd1 = mSldFirstProdValue;
setEnableDisableProdButt(btnFirstProdClear, btnFirstProdAccept, false);
setClearProd(txtFirstProd, sldFirstProd, lblSldFirstProd);
setEnableDisableProdData(txtFirstProd, sldFirstProd, false);
}
public void onClearSecondProducer(ActionEvent e) {
setClearProd(txtSecondProd, sldSecondProd, lblSldSecondProd);
}
public void onAcceptSecondProducer(ActionEvent e) {
nameOfProd2 = txtSecondProd.getText();
timeOfProd2 = mSldSecondProdValue;
setEnableDisableProdButt(btnSecondProdClear, btnSecondProdAccept, false);
setClearProd(txtSecondProd, sldSecondProd, lblSldSecondProd);
setEnableDisableProdData(txtSecondProd, sldSecondProd, false);
}
public void setEnableDisableProdData(TextField txtProdName, Slider sldProd, boolean toActivDeactiv) {
if(toActivDeactiv) {
txtProdName.setDisable(false);
sldProd.setDisable(false);
} else {
txtProdName.setDisable(true);
sldProd.setDisable(true);
}
}
public void setEnableDisableProdButt(Button clear, Button accept, boolean toActivDeactiv) {
if(toActivDeactiv) {
clear.setDisable(false);
accept.setDisable(false);
} else {
clear.setDisable(true);
accept.setDisable(true);
}
}
public void setClearProd(TextField txtProdName, Slider sldProd, Label sldValueInfo) {
txtProdName.setText("");
sldProd.setValue(0);
sldValueInfo.setText("500 ms");
}
public static void setTxtAreaOfProd(String input) {
txtProdInfo.setText(input);
}
public static void setTxtAreaOfCons(String input) {
txtConsInfo.setText(input);
}
}
Producer.java:
package com.example.case4javafx;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import java.util.LinkedList;
import java.util.List;
public class Producer extends Task<Void> {
private final LinkedList<String> dataOfProducts;
private final String nameOfProducer;
private final int timeOfProduction;
private final int capacity;
private Object lock;
public Producer(LinkedList<String> refToData, String nameOfProducer, int timeOfProduction, Object lock) {
this.dataOfProducts = refToData;
this.nameOfProducer = nameOfProducer;
this.timeOfProduction = timeOfProduction;
this.capacity = 10;
this.lock = lock;
}
@Override
protected Void call() throws InterruptedException {
int value = 0;
while (true) {
synchronized (lock) {
System.out.println("I'm a producer");
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
while (dataOfProducts.size() == capacity) {
lock.wait();
}
updateMessage("Producer produced-" + value);
// to insert the jobs in the list
String itemToAdd = nameOfProducer + " " + Integer.toString(value++);
dataOfProducts.add(itemToAdd);
// notifies the consumer thread that
// now it can start consuming
lock.notify();
// makes the working of program easier
// to understand
try {
Thread.sleep(this.timeOfProduction);
} catch (InterruptedException e) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
}
}
}
return null;
}
}
Consumer.java:
package com.example.case4javafx;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
public class Consumer extends Task<Void> {
private final Object lock;
private final LinkedList<String> dataOfProducts;
public Consumer(LinkedList<String> dataOfProducts, Object lock) {
this.dataOfProducts = dataOfProducts;
this.lock = lock;
}
@Override
protected Void call() throws InterruptedException {
int value = 0;
while (true) {
synchronized (lock) {
System.out.println("I'm a consumer");
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
while (dataOfProducts.size() == 0) {
lock.wait();
}
// to insert the jobs in the list
String resultOfProducer = dataOfProducts.removeFirst();
// notifies the consumer thread that
// now it can start consuming
lock.notify();
// makes the working of program easier
// to understand
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
}
}
}
return null;
}
}
Producer and Consumer classes are extending Task abstract class and both are implementing abstract method call().
If you know the answer to this problem ("sending" String data from Thread Producer / Consumer with assignment "mission" to both of this TextAreas accordingly) I would be very thankful.