0

I'm trying to sum the similar threads inside the ExecutorService. I think I should use join() method, but I wasn't able to do it correctly.

My Code:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

public class Gui extends JFrame implements ActionListener{
    private JTextField txtSeats, txtAgents, txtTime;
    public int numFirst, numSecond, numThird;
    private JTextArea [] bookSeat;
    private JButton btn1, btn2;
    private String output, name;
    private Random ran;
    private JPanel p1, p2;
    private String [] agentNumber;
    private int [] sum;
    private int x, z;

    public Gui() {//A constructor for the Gui class.

        ran = new Random();//Initializing the Random class.


        setLayout(new BorderLayout());//Setting the layout for the JFrame.
        setTitle("");//the title of the program.


        p1 = new JPanel();//Creating the first JPanel to add JButtons and JTextField on it.
        p1.setLayout(new FlowLayout());//Setting the first JPanel's layout.


        //Creating 3 JTextField with a title for each, and adding each of them to the first JPanel.
        txtSeats = new JTextField("Number of seats");
        p1.add(txtSeats);

        txtAgents = new JTextField("Number of agents");
        p1.add(txtAgents);

        txtTime = new JTextField("Max waiting time");
        p1.add(txtTime);


        //Creating 2 JButton with a title for each, and adding each of them to the first JPanel.
        btn1 = new JButton("Create seats");
        p1.add(btn1);

        btn2 = new JButton("Book");
        p1.add(btn2);


        //Registering the 2 JButton to the ActionListener so they work with the actionPerformed() method when they get clicked.
        btn1.addActionListener(this);
        btn2.addActionListener(this);


        add(p1, BorderLayout.NORTH);//Adding the first JPanel to the main JFrame at the position NORTH.


        //Giving some properties to the JFrame layout. 
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setResizable(false);
    }//End of the constructor.



    public void createSeat() {//A method for creating a number of empty seats depending on the users wish.

            //Storing the value of the first JTextField into an integer variable. 
            //With removing the spaces in it if there is any using "trim()".
            numFirst = Integer.parseInt(txtSeats.getText().trim());


            //Creating a JTextArea array for the number of seats the user wants to add.
            //The size is entered by the user.
            bookSeat = new JTextArea[numFirst];


            p2 = new JPanel(); //Creating the second JPanel to add JTextArea on it.
            p2.setLayout(new FlowLayout()); //Setting the second JPanel's layout.


            //for-loop for adding the new JTextArea array into the second JPanel.
            //With setting their title and background color and other properties.
            for(int i = 0; i < numFirst; i++) {
                bookSeat[i] = new JTextArea("Not booked");
                bookSeat[i].setBackground(Color.WHITE);
                bookSeat[i].setEditable(false);
                p2.add(bookSeat[i]);
                add(p2, BorderLayout.CENTER);//Adding the second JPanel to the main JFrame at the position CENTER.
                setVisible(true);
            }
    }//End of createSeat() method.

    @Override
    public void actionPerformed(ActionEvent e) {//A method Overrode from the ActionListener interface.

        if(e.getSource().equals(btn1)) {//First case: The JButton "Create seats" is clicked.

            //Calling the createSeat() method; to create an empty seats based on the entered number of seats in the first JTextField.
            createSeat();

            //This method called on a container once new components are added or old ones removed. 
            //This call is an instruction to tell the layout manager to reset based on the new component list.
            //revalidate() will trigger a call to repaint what the component thinks are 'dirty regions.'
            //https://stackoverflow.com/questions/1097366/java-swing-revalidate-vs-repaint
            revalidate();
        }
        else if(e.getSource().equals(btn2)) {//Second case: The JButton "Book" is clicked.

            //Storing the values of the second and third JTextField into 2 integer variables.
            //With removing the spaces in them if there is any using "trim()".
            numSecond = Integer.parseInt(txtAgents.getText().trim());
            numThird = Integer.parseInt(txtTime.getText().trim());


            //Creating an ExecutorService object with fixed thread pool with maximum number of agents threads.
            ExecutorService executor = Executors.newFixedThreadPool(numSecond);

            //for-loop for the number of times the ExecutorService (thread pool) should run.
            //It will keep creating threads until it reaches the maximum number of seats.
            for(int i = 0; i < numFirst; i++) {
                int count = i;

                //Submitting Runnable task to the executor.
                executor.execute(new Runnable() {

                @Override
                public void run() {//A method Overrode from the Runnable interface.
                    try {
                        //Getting the name of the current thread & store it in a String variable.
                        //Then we will have a long name like: pool-1-thread-n (n is a changing thread number). 
                        //We use split("-"); to split it to 4 parts and we take the 4 part which is in position [3].  
                        name = Thread.currentThread().getName();
                        agentNumber = name.split("-");


                        //Setting the new text and background color to the JTextArea array after they get booked.
                        bookSeat[count].setText("Booked by Agent " + agentNumber[3]);
                        bookSeat[count].setBackground(Color.RED);

                        revalidate();

                        //Generating random number between 0 and the waiting time entered by the user.
                        //And inserting this value inside the sleep() method. For a waiting time between each thread.
                         x = ran.nextInt(numThird + 1);
                        Thread.currentThread().sleep(x);
                    }
                    catch (Exception e) {}
                }//End of run() method.
                });//End of the executor.
            }//End of the for-loop.


            //Temporary solution for finding the similar elements in the array and return the sum for each 
            //equal threads. BUT NOT WORKING!!!
            z = 0;
            for(int i = 0; i < numFirst;i++) {
                for(int j = 0; j < numFirst; j++) {
                    if(bookSeat[i].getName().equals(bookSeat[j].getName())) {
                        sum[i] = z + 1; 
                    }
                }
            }


            //for-loop for storing the booked seats in a String variable.
            output = "";
            for(int i = 1; i <= numSecond; i++) {
                    String allAgents = String.valueOf(i);
                    output += ("\n" + "Agent " + allAgents +  " booked " + sum + " seats.");
            }

            //Displaying a Message Dialog with the information of each agent's booking.
            JOptionPane.showMessageDialog(this,output);


            //Shutdown the executor.
            executor.shutdown();


            //Wait until all tasks are finished.
            while(!executor.isTerminated()) {
                System.out.println("The booking has finished");
            }
        }//End of else if condition.
    }//End of actionPerformed() method.

    public static void main(String [] args) {//Main method.
        new Gui(); //Calling the Gui.
    }//End of Main method.
}//End of the class.

As you may see, I have tried with doing a nested for loop for checking the elements in the array if they were similar and return the sum of them. But this still didn't work!

        z = 0;
        for(int i = 0; i < numFirst;i++) {
            for(int j = 0; j < numFirst; j++) {
                if(bookSeat[i].getName().equals(bookSeat[j].getName())) {
                    sum[i] = z + 1; 
                }
            }
        }
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
White Puzzle
  • 19
  • 2
  • 6

1 Answers1

0

Using Executor you loose direct access to the Thread instance which is needed for waiting for it (e.g. join()).

First create an array of Threads, then start them, then join() them. E.g.:

    int numSecond = 3;

    Runnable r = new Runnable() {
        @Override
        public void run() 
        {
            // do your stuff inside thread
        }//End of run() method.
    };

    IntStream.range(1,numSecond + 1).forEach( i -> {
        Thread t = new Thread( r, "pool-1-thread-" + i);
        t.start();

        try
        {
            t.join();
        }
        catch ( InterruptedException t1 )
        {
            System.err.println( "thread interrupted" );
        }
    });

Above example names the thread as you expect in your code:

"pool-1-thread-" + i

If you are only interested in the numer then just pass in

"" + i

Using CompletableFutures might solve the problem also in an elegant way.

BTW1: Using a sleep(x) at the end of the thread's run method is absolutely senseless. It does not delay the start time of another thread. Why at all you want to do this? If you want to execute the logic in run() in a sequential way, there is no need to create use threads at all.

BTW2: Next time you asking something please boil down your code to a minimum which shows your problem. There is no need to setup a whole GUI with buttons, klick handlers etc.

BTW3: The access to shared (global) variables from inside the threads must be synchronized.

Heri
  • 4,368
  • 1
  • 31
  • 51