0

Hello guys so i have to make two threads that sell train tickets simultaneously and display there output on two different windows, i have create a class that generates the tickets and a Runnable but i am not sure how to display the output of the two different threads in the two different Text area boxes i have tried to pass the TextBox parameter but it didn't work any ideas please ?

SellTicketThreadProc:

public class SellTicketThreadProc implements Runnable {
    private CTicketBiz cTicketBiz;

    public SellTicketThreadProc(CTicketBiz newobj){
        cTicketBiz = newobj;
    }

    public  void sellticket(){
        String color;
        switch(Thread.currentThread().getName()){
            case "Thread 1":
                color = ThreadColor.ANSI_CYAN;
                break;
            case "Thread 2":
                color = ThreadColor.ANSI_PURPLE;
                break;
            default:
                color = ThreadColor.ANSI_GREEN;
        }

        System.out.println(color + Thread.currentThread().getName() + " Random number: " + cTicketBiz.GetRandTicket() + "  Remaining tickets are: " + cTicketBiz.GetBalanceNum() );


    }

    @Override
    public void run() {
        while (cTicketBiz.GetBalanceNum() != 0) {
            sellticket();
        }
    }
}

CTicketBiz:

public class CTicketBiz {

    private int[] m_pTicket; //Point to the array that saves the ticket information
    private int m_nSoldNum; // Sold ticket number
    private int m_nBalanceNum; // Remaining ticket number
    private int m_nTotalNum;



    // Generate the ticket. Initialize the movie ticket array.
    void GenerateTicket(int totalTickets){
        m_nTotalNum = totalTickets;
        m_pTicket = new int[m_nTotalNum];
        m_nBalanceNum = m_nTotalNum;
        m_nSoldNum = 0;
        for (int i = 0; i < m_nTotalNum; i++) {
            m_pTicket[i] = i + 1;
        }
    }


    // Get a ticket randomly
    public synchronized int GetRandTicket(){
        if (m_nBalanceNum <= 0)
            return 0;
        int temp = 0;
        do {
            temp = new Random().nextInt(m_pTicket.length);
        } while (m_pTicket[temp] == 0);
        m_pTicket[temp] = 0;
        m_nBalanceNum--;
        m_nSoldNum++;
        return temp + 1;
    }
    // Get the remaining ticket number
    int GetBalanceNum(){
        return m_nBalanceNum;

    }

}

Controller:

import javafx.fxml.FXML;
import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.control.TextArea;

public class Controller {


    @FXML
    private TextField ticketsToSell;
    @FXML
    private Button startSelling;
    @FXML
    private TextArea displayThread1;
    @FXML
    private TextArea getDisplayThread2;
    @FXML
    public void onButtonClicked(ActionEvent e){
        if(e.getSource().equals(startSelling)){
            CTicketBiz cTicketBiz = new CTicketBiz();
            cTicketBiz.GenerateTicket(6);
            SellTicketThreadProc tw = new SellTicketThreadProc(cTicketBiz);
            Thread t1 = new Thread (tw,"Thread 1");
            Thread t2 = new Thread (tw,"Thread 2");
            t1.start();
            t2.start();

        }

        }

        @FXML
    public  void handleKeyReleased(){
            String text = ticketsToSell.getText();
            boolean disableButton = text.isEmpty() || text.trim().isEmpty();
            startSelling.setDisable(disableButton);
        }
}
Matt
  • 3,052
  • 1
  • 17
  • 30
Nabreezy
  • 41
  • 1
  • 4
  • 4
    What exactly *didn't work*? Did you get any output on any of the two `TextArea`s or was there no output at all? – deHaar Oct 28 '19 at 15:20
  • 1
    [mcve] please .. and unrelated to your problem: please learn java naming conventions and stick to them. – kleopatra Oct 28 '19 at 15:26
  • Hi guys Sorry if the code is bad or anything i am still learning and there is an output in the console but not on the text area. I tried to return the string and append that to the TextArea but since both Threads are using it it did not work . – Nabreezy Oct 28 '19 at 15:35
  • @kleopatra fully noted thank you for the feedback – Nabreezy Oct 28 '19 at 15:37
  • You probably need to make `GetBalanceNum()` synchronized. An unsynchronized method is not guaranteed to see changes to variables made by other threads. See [the Java Language Specification §17.3](https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.3). – VGR Oct 28 '19 at 16:03
  • You should look into JavaFX concurrency which uses Task and Service which provides methods to update the UI as they complete, rather than just using Thread. – purring pigeon Oct 28 '19 at 17:12

1 Answers1

3

Here is a quick runnable application to demonstrate how to update 2 separate textareas from background threads like you have make sure to read through the comments that explain whats going on. Obviously this is not the same exact thing as your program but I kept the core concept.

public class Main extends Application {

    private AtomicInteger totalTickets = new AtomicInteger(100);
    private boolean isSellingTickets = false;

    @Override
    public void start(Stage stage) {
        VBox vBoxContainer = new VBox();
        vBoxContainer.setAlignment(Pos.CENTER);
        vBoxContainer.setPrefSize(400,250);

        TextArea textAreaTop = new TextArea();
        TextArea textAreaBottom = new TextArea();
        vBoxContainer.getChildren().addAll(textAreaTop, textAreaBottom);

        Button controlSalesButton = new Button("Start Ticket Sales");
        controlSalesButton.setOnAction(event -> {
            if(isSellingTickets) {
                isSellingTickets = false;
                controlSalesButton.setText("Start Ticket Sales");
            }
            else {
                isSellingTickets = true;
                //I didn't name these threads because I never reference them again
                // of course create var name if you need them
                new Thread(() -> sellTickets(textAreaTop)).start();
                new Thread(() -> sellTickets(textAreaBottom)).start();

                // This is on the main Thread so no need for Platform.runLater(...)
                controlSalesButton.setText("Stop Ticket Sales");
            }

        });
        vBoxContainer.getChildren().add(controlSalesButton);

        stage.setScene(new Scene(vBoxContainer));
        stage.show();
    }

    private void sellTickets(TextArea textArea){//This Whole Function is on another thread don't forget about that
        while(isSellingTickets && totalTickets.get()>1) { //Continue selling tickets until you stop
            // And Make Sure there is tickets to sell

            //Platform.runLater(... is used to update the main thread by pushing updates to
            // the JavaFX Application Thread at some unspecified time in the future.
            Platform.runLater(() -> {
                textArea.appendText("SOLD Ticket Number:" + (int) (Math.random() * 1000 + 1000) + " \t"
                        + totalTickets.decrementAndGet() + " Left to sell\n");
            });

            try {
                Thread.sleep((int) (Math.random() * 1000 + 100));//Different selling speeds this is irrelevant
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

If you have any questions let me know

Matt
  • 3,052
  • 1
  • 17
  • 30