【问题标题】:Modify and access value outside a thread class修改和访问线程类之外的值
【发布时间】:2017-10-17 12:10:31
【问题描述】:

我是 OOP 的新手,尤其是 Java。所以,我很难从两个类中访问和删除 ArrayList 中的值。

我有一个 Counter 类,其中我只有一个 ArrayList,我必须从两个不同的类中调用它。

public class Counter12 {
   public static ArrayList<String> clientsStorage = new ArrayList<String>();
}

Server12

public class Server12 {
//public static int counter = 0;
public static void main(String[] argv) throws Exception {

    //Create a server socket, bounds to a specified port
    ServerSocket serverSocket = new ServerSocket(5016);
    System.out.println("Server started");
    //int counter = 0;
    //ArrayList<String> clientsStorage = new ArrayList<String>();

    while (true) {
        //counter++;
        Socket serverClient = serverSocket.accept();    //Wait for client to connect      
        ServerClientThread sct = new ServerClientThread(serverClient);
        sct.start();          
    }
}

ServerClientThread 是一个线程类,我在 ArrayList 中添加一些值

public class ServerClientThread extends Thread{

Socket serverClient;
//int counter;

//int counter = 0;
   ServerClientThread(Socket inSocket) {
       serverClient = inSocket;
       //clientNo = counter;

}

   private volatile ArrayBlockingQueue<String> clientsStorage = new ArrayBlockingQueue<String>(10);
   //ArrayList<String> clientsStorage = new ArrayList<String>();
public void run(){  
      //counter++;
      try {
          ObjectInputStream inputValues = new ObjectInputStream(serverClient.getInputStream());
          Student12 received = (Student12) inputValues.readObject();

          if (received.getName().equals("Wrong!")) {

                //represent object to a text-output stream
                //System.out.println("Clients connected: " + clientNo);
                PrintWriter output = new PrintWriter(serverClient.getOutputStream(), true);
                output.println("Wrong typed value.Try again!");
                output.println("Name: Johny Domino Domino");
                output.println("Age: 27");
                output.println("Mark: 2");
                output.println("Email: johny_domino@gmx.com");
               // output.println("Clients connected: " + clientNo);
               inputValues.close();
                output.close();
                //serverClient.close();


            } 
            else {
                Counter12.clientsStorage.add(received.getName());
                int clientsNumber = Counter12.clientsStorage.size();

                System.out.println("Clients: " + clientsNumber);
                System.out.println("Client accepted: " + received.getName());
                PrintWriter output = new PrintWriter(serverClient.getOutputStream(), true);
                output.println("Student " + received.getName() + received.getEmail() + " has been received");
               output.println("Clients: " + clientsNumber);
                inputValues.close();
                output.close();
                //serverClient.close();

            }


    } catch (Exception e) {
        // TODO: handle exception
    }
  }  

}

Client 类中,我应该从 ArrayList 中删除一些值,但我不能,因为程序显示 ArrayList 是空的

private static final long serialVersionUID = 7526472295622776147L;
//Creating fields, labels and area using JFrame class
JLabel labelName;
JLabel labelAge;
JLabel labelMark;
JLabel labelEmail;

JTextField txtFieldName;
JTextField txtFieldAge;
JTextField txtFieldMark;
JTextField txtFieldEmail;

JButton btnProcess;
JButton btnAddClient;
JButton btnLeave;
JButton btnExit;


JTextArea txtArea;



public Client12() {

     //Set parameters   
    this.setTitle("Simple Sample");
    this.setSize(420, 300);
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    getContentPane().setLayout(null);

    labelName = new JLabel("Full Name: ");
    labelName.setBounds(10, 10, 120, 21);
    add(labelName);


    txtFieldName = new JTextField(); 
    txtFieldName.setBounds(105, 10, 120, 21);
    add(txtFieldName);

    labelAge = new JLabel("Age: ");
    labelAge.setBounds(10, 35, 120, 21);
    add(labelAge);

    txtFieldAge = new JTextField();
    txtFieldAge.setBounds(105, 35, 120, 21);
    add(txtFieldAge);

    labelMark = new JLabel("Mark: ");
    labelMark.setBounds(10, 60, 120, 21);
    add(labelMark);

    txtFieldMark = new JTextField();
    txtFieldMark.setBounds(105, 60, 120, 21);
    add(txtFieldMark);

    labelEmail = new JLabel("Email: ");
    labelEmail.setBounds(10, 85, 120, 21);
    add(labelEmail);

    txtFieldEmail = new JTextField();
    txtFieldEmail.setBounds(105, 85, 120, 21);
    add(txtFieldEmail);

    btnProcess = new JButton("Process");
    btnProcess.setBounds(250, 40, 120, 21);
    btnProcess.addActionListener(this);
    add(btnProcess);

    btnAddClient = new JButton("Add Client");
    btnAddClient.setBounds(250, 70, 120, 21);
    btnAddClient.addActionListener(this);
    add(btnAddClient);

    btnLeave = new JButton("Client Leave");
    btnLeave.setBounds(250, 100, 120, 21);
    btnLeave.addActionListener(this);
    add(btnLeave);

    btnExit = new JButton("Exit");
    btnExit.setBounds(250, 130, 120, 21);
    btnExit.addActionListener(this);
    add(btnExit);

    txtArea = new JTextArea();
    txtArea.setBounds(10, 120, 385, 150);
    txtArea.setLineWrap(true);
    txtArea.setWrapStyleWord(true);
    add(txtArea);


    this.setVisible(true);

}

public static void main(String[] args){
    new Client12(); 
}


@Override
public void actionPerformed(ActionEvent event) {
    if (event.getSource().equals(btnProcess)) {
        try {
            processInformation();
        } catch (UnknownHostException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
    }
    else if (event.getSource().equals(btnAddClient)){
        new Client12();
    }

    else if (event.getSource().equals(btnLeave)){

        Counter12.clientsStorage.remove(0);
        System.out.println("Clients: " + Counter12.clientsStorage.size());
        setVisible(false);
        dispose(); //Destroy the JFrame object.
    }

    else if (event.getSource().equals(btnExit)){
        dispose();
        System.exit(0);
    }
}


//Method that process input information
public void processInformation() throws UnknownHostException, IOException {

    Socket s = new Socket("localhost", 5016);
    ObjectOutputStream p = new ObjectOutputStream(s.getOutputStream());

    String name = txtFieldName.getText();
    String markStr = txtFieldMark.getText();
    String ageStr = txtFieldAge.getText();   
    String email = txtFieldEmail.getText();

    //Checks if the user entered a properly formatted name, mark, age and email
    //RegEx name
    String patternName = ("^[A-Z]+[a-z]+\\s[A-Z]+[a-z]+\\s[A-Z]+[a-z]+$");
    Pattern patternCompileName = Pattern.compile(patternName);
    Matcher matcherName = patternCompileName.matcher(name);

    //RegEx mark
    String patternMark = ("^[0-6]$");
    Pattern patternCompileMark = Pattern.compile(patternMark);
    Matcher matcherMark = patternCompileMark.matcher(String.valueOf(markStr));

    //RegEx age
    String patternAge = ("\\d");
    Pattern patternCompileAge = Pattern.compile(patternAge);
    Matcher matcherAge = patternCompileAge.matcher(String.valueOf(ageStr));

    //RegEx email
    String patternEmail = ("[A-z0-9._%+-]+@[A-z0-9.-]+\\.[A-z]{2,5}");
    Pattern patternCompileEmail = Pattern.compile(patternEmail);
    Matcher matcherEmail = patternCompileEmail.matcher(email);

    int mark = 0;
    int age = 0;

    //Match the regular expressions
    if (matcherName.find() && matcherMark.find() && matcherAge.find() && matcherEmail.find()) {

         //counter++;
         mark = Integer.parseInt(markStr);
         age = Integer.parseInt(ageStr);
         //writes primitive data of the object to an OutputStream
         p.writeObject(new Student12(name, age, mark, email));
         p.flush();

        //Read the details from server
         BufferedReader response = new BufferedReader(new InputStreamReader(
                 s.getInputStream()));

         txtArea.setText("The server respond: " + response.readLine() + "\r\n");
         txtArea.append(response.readLine() + "\r\n");
         btnProcess.setEnabled(false);
         p.close();   
         response.close();
         s.close();
        // txtFieldName.setText("");
         //txtFieldAge.setText("");
        // txtFieldMark.setText("");
        // txtFieldEmail.setText("");
    }
    else {
        //If RegEx is false, we will set name = "Wrong!"
        p.writeObject(new Student12("Wrong!", age, mark, email));
        p.flush();

     BufferedReader response = new BufferedReader(new InputStreamReader(
                s.getInputStream()));

         txtArea.setText("The server respond: " + response.readLine() + "\r\n");
         txtArea.append("Example: " + "\r\n");
         txtArea.append(response.readLine() + "\r\n");
         txtArea.append(response.readLine() + "\r\n");
         txtArea.append(response.readLine() + "\r\n");
         txtArea.append(response.readLine());
         p.close();
         response.close();
         s.close();

        // txtFieldName.setText("");
         //txtFieldAge.setText("");
        // txtFieldMark.setText("");
         //txtFieldEmail.setText("");
    }  
}

我应该怎么做才能从 ServerClientThread 类中添加值并将它们从 Client 类中删除?

【问题讨论】:

  • 在语言新手的同时做多线程就像在学习航行的同时在海洋中航行。
  • 感谢您的建议,但这是大学作业。我必须这样做!

标签: java multithreading oop arraylist


【解决方案1】:

您似乎将 ArrayList 用作队列:您在末尾添加,并从开头删除。所以最好使用Queue接口。多线程应用程序的典型队列实现是ArrayBlockingQueue。使用它而不是 ArrayList

似乎您的一个线程试图在另一个线程写入之前从您的数组列表中读取一个值。使用ArrayBlockingQueue,读取线程会等待其他线程写入值。

【讨论】:

  • 问题是我试图通过客户端类删除线程。我有一些 JFrame 文本框,当我单击添加客户端时,它会将其添加到 Counter 类中。当我尝试删除它时,列表为空。没有附加价值...
  • 您确定要在添加值后从数组列表中删除吗?在我看来,您正在并行运行两个线程,并且删除值的线程尝试在添加值之前这样做。
  • 是的,我也这么认为。我将编辑代码以使其更清晰。
  • 在您更新的代码中,共享“队列”Counter12.clientsStorage 仍然只是一个 ArrayList。您似乎在类 ServerClientThread 中创建了一个同名的私有 ArrayBlockingQueue 变量,您根本不使用它。您是否尝试将Counter12.clientsStorage 更改为 ArrayBlockingQueue?
  • 是的,我试过了。我只是粘贴旧代码并没有删除我尝试过的一些修改。我尝试了你告诉我的一切。问题是我试图删除该值,但显然它没有被添加。但我不明白为什么。当我签入线程类时,它被添加,但是当我尝试从客户端类中删除它时,它不存在。也许我应该尝试以不同的方式删除它,但不知道如何。这是我在这个项目中要做的最后一件事。只是为了做计数器,当我关闭其中一个线程时,计数器会减少。
【解决方案2】:
  1. ArrayList 更改为CopyOnWriteArrayList。它是线程安全的。如果您使用线程,请考虑使用 synchronize 块、java.util.concurrent 中的线程安全类或 Guava 库中的线程安全集合。

  2. 另外,如果您使用线程,请考虑不使用静态字段。

  3. 如果您希望一个线程提供一些值,而另一个线程检索它们,请考虑将List&lt;&gt; 更改为其他集合,例如StackQueue

  4. 为了更简洁的代码,尝试利用 java 多态机制: List<String> list = new ArrayList<>();

【讨论】:

  • 我尝试使用 List list = new ArrayList() 并删除“静态”,但它是相同的。我认为问题出在我的 Counter12 课程中。也许我应该使用一些 getter 和 setter...
  • List&lt;String&gt; 仅适用于干净的代码 :) 尝试使用 CopyOnWriteArrayList
【解决方案3】:

决定是在按下“离开客户端”按钮后,我必须在“客户端”类中创建一个新方法。在这个方法中,我创建了一个新的套接字、输出流,并创建了一个具有唯一名称的新学生,以便进入 Thread 类中的 run() 方法(通过“BufferedReader”)。之后在线程中我使用 take() 方法从 ArrayBlockingQueue 中删除队列。

客户端

 else if (event.getSource().equals(btnLeave)){
        if (!btnProcess.getModel().isEnabled()) {
            try {
                removeClient();
            } catch (UnknownHostException e1) {
                e1.printStackTrace();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            setVisible(false);
            dispose(); //Destroy the JFrame object.
        }
    }

public void removeClient()throws UnknownHostException, IOException {

    Socket s = new Socket("localhost", 5016);
    ObjectOutputStream p = new ObjectOutputStream(s.getOutputStream());

    p.writeObject(new Student("Remove Client!", 27, 2, "remove_client@gmx.com"));
    p.flush();

    BufferedReader response = new BufferedReader(new InputStreamReader(s.getInputStream()));

    txtArea.setText("The server respond: " + response.readLine() + "\r\n");
}

ServerClientThread

else if (received.getName().equals("Remove Client!")) {

              Counter.clientsStorage.take();
              System.out.println("Client removed");
              System.out.println("Clients: " + Counter.clientsStorage.size());
              PrintWriter output = new PrintWriter(serverClient.getOutputStream(), true);
              output.println("Student removed");
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-30
    • 1970-01-01
    • 2018-01-15
    • 2012-04-19
    • 1970-01-01
    相关资源
    最近更新 更多