【问题标题】:How to sum the similar threads inside ExecutorService in java?java - 如何在java中对ExecutorService中的类似线程求和?
【发布时间】:2019-11-17 15:27:33
【问题描述】:

我正在尝试总结 ExecutorService 中的类似线程。我认为我应该使用 join() 方法,但我无法正确使用。

我的代码:

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.

如您所见,我尝试使用嵌套 for 循环来检查数组中的元素是否相似并返回它们的总和。但这仍然不起作用!

        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; 
                }
            }
        }

【问题讨论】:

    标签: java arrays multithreading user-interface executorservice


    【解决方案1】:

    使用 Executor 您可以直接访问等待它所需的 Thread 实例(例如 join())。

    首先创建一个线程数组,然后启动它们,然后加入()它们。例如:

        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" );
            }
        });
    

    以上示例按照您在代码中的预期命名线程:

    "pool-1-thread-" + i
    

    如果你只对数字感兴趣,那么直接传入

    "" + i
    

    使用 CompletableFutures 也可以优雅地解决问题。

    BTW1:在线程的 run 方法结束时使用 sleep(x) 绝对没有意义。它不会延迟另一个线程的启动时间。你为什么要这样做?如果你想按顺序执行run()中的逻辑,根本不需要创建使用线程。

    BTW2:下次您提出问题时,请将您的代码精简到显示您的问题的最低限度。无需使用按钮、klick 处理程序等设置整个 GUI。

    BTW3:必须同步从线程内部访问共享(全局)变量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-20
      • 2019-03-15
      • 2012-04-02
      • 1970-01-01
      • 2020-09-24
      • 2011-08-22
      • 1970-01-01
      • 2011-12-22
      相关资源
      最近更新 更多