多线程不是 运行 并行

Multithreading not running on parallel

我 3 天前开始学习 Java 编程,之前我只能编写代码 PHP 等。现在我遇到了一个问题 - 我试图与多个服务器进行客户端聊天客户端,连接时客户端的数据存储在一个数组中(套接字、数据输入流和数据输出流)。无论如何,一切都按应有的方式编译,但我使用了 2 个具有可运行接口的线程,但这些线程不是 运行 并行。首先我启动了服务器,然后我启动了第一个客户端。第一个客户端说它已连接到服务器,但服务器无法识别它。当启动第二个客户端时,服务器识别它并将数据保存在数组中,但是当尝试使用 writeUTF() 从客户端写入文本时,服务器的 MessageTransport 线程不起作用。这是完整的代码,我将 javafx 与 fxmlloader 一起使用:
聊天服务器:

import java.net.*;
import java.io.*;
import java.util.*;

class ClientHandler extends Server implements Runnable{

    private Thread t;
    private String threadName;

    ClientHandler(String name){
        threadName = name;
        System.out.println("Creating thread: " + name);
    }

    public void run(){
        System.out.println("Running thread: " + threadName);
        /*try{
            Thread.sleep(500);
        }catch(Exception e){
            e.printStackTrace();
        }*/
        System.out.println("Waiting for clients...");
        while(true){
            try{
                Socket s;
                if((s = ss.accept()) != null){
                    clientSockets.add(s);
                    DataInputStream din = new DataInputStream(s.getInputStream());
                    dinStreams.add(din);
                    DataOutputStream dout = new DataOutputStream(s.getOutputStream());
                    doutStreams.add(dout);

                    System.out.println("Client connected. Added to list.");
                }
            }catch(Exception e){
                e.printStackTrace();
                break;
            }
        }
    }
    public void start(){
        System.out.println("Starting thread: " + threadName);
        if(t == null){
            t = new Thread(this, threadName);
            t.start();
        }else{
            System.out.println("Failed to start thread " + threadName + ". Thread already started.");
        }
    }
}

class MessageTransport extends Server implements Runnable{

    private Thread t;
    private String threadName;

    MessageTransport(String name){
        threadName = name;
        System.out.println("Creating thread: " + name);
    }

    public void run(){
        System.out.println("Running thread: " + threadName);
        /*try{
            Thread.sleep(1000);
        }catch(Exception e){
            e.printStackTrace();
        }*/
        System.out.println("Ready to transport messages...");
        while(true){
            int i;
            for(i=0;i<clientSockets.size();i++){
                try{
                    DataInputStream din = dinStreams.get(i);
                    if(!din.readUTF().equals("")){
                        int v;
                        for(v=0; v<clientSockets.size(); v++){
                            DataOutputStream dout = doutStreams.get(v);
                            dout.writeUTF(din.readUTF());
                            dout.flush();
                        }
                    }else if(din.readUTF().equals("/System_exit")){
                        System.out.println("Client left.");
                        din.close();
                        clientSockets.remove(i);
                        dinStreams.remove(i);
                        doutStreams.remove(i);
                    }
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
    }
    public void start(){
        System.out.println("Starting thread: " + threadName);
        if(t == null){
            t = new Thread(this, threadName);
            t.start();
        }else{
            System.out.println("Failed to start thread " + threadName + ". Thread already started.");
        }
    }
}

public class Server {

    public static ServerSocket ss;
    public static List<Socket> clientSockets;
    public static List<DataInputStream> dinStreams;
    public static List<DataOutputStream> doutStreams;

    public static void main(String[] args){
        try{
            ss = new ServerSocket(5000);
            clientSockets = new ArrayList<>();
            dinStreams = new ArrayList<>();
            doutStreams = new ArrayList<>();

            System.out.println("Server opened. Waiting for clients");
            ClientHandler CH = new ClientHandler("Client_Handler");
            CH.start();
            MessageTransport mt = new MessageTransport("Message Transmitter");
            mt.start();

        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

聊天客户端文件... 主要 class:

package sample;

import javafx.application.Application;

import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.net.*;
import java.io.*;

public class Main extends Application{

    private static Socket s = null;
    private static Controller controller;
    private static String username = "priitkaard";
    private static DataOutputStream dout = null;
    private static DataInputStream din = null;

    @Override
    public void start(Stage primaryStage) throws Exception{
        FXMLLoader loader = new FXMLLoader(getClass().getResource("chat_client.fxml"));
        VBox layout = loader.load();
        controller = loader.getController();

        primaryStage.setTitle("Chatbox");
        primaryStage.setScene(new Scene(layout, 600, 300));
        primaryStage.show();
        primaryStage.setOnCloseRequest(e -> {
            e.consume();
            if(s != null){
                try{
                    if(dout != null){
                        dout.writeUTF("/System_exit");
                    }
                    s.close();
                }catch(Exception l){
                    l.printStackTrace();
                }
            }
            Platform.exit();
        });
        try{
            s = new Socket("localhost", 5000);
            controller.writeln("Connected to the server.");
            din = new DataInputStream(s.getInputStream());
            dout = new DataOutputStream(s.getOutputStream());
        }catch(ConnectException cE){
            controller.writeln("Couldn't connect to the server.");
        }
        MessageListener ml = new MessageListener();
        ml.start();
    }
    public static Socket getSocket(){
        return s;
    }
    public static DataInputStream getDin(){
        return din;
    }
    public static DataOutputStream getDout(){
        return dout;
    }
    public static Controller getChatController(){
        return controller;
    }
    public static String getUsername(){
        return username;
    }

    public static void main(String[] args) { launch(args); }
}
class MessageListener implements Runnable{
    private String threadName;
    private Thread t;
    MessageListener(){
        threadName = "messageListener";
    }
    @Override
    public void run() {
        if(Main.getSocket() != null){
            try{
                DataInputStream din = Main.getDin();
                while(true){
                    if(!din.readUTF().equals("")){
                        Main.getChatController().writeln(din.readUTF());
                    }
                }
            }catch(Exception e){
                Main.getChatController().writeln("No connection.");
                e.printStackTrace();
            }
        }
    }
    public void start(){
        if(t == null){
            t = new Thread(this, threadName);
            t.start();
        }
    }
}

控制器class:

package sample;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;

import java.io.DataOutputStream;


public class Controller {
    @FXML
    private TextArea a;
    @FXML private TextField b;

    public void writeln(String message){
        a.setText(a.getText() + "\n" + message);
    }

    @FXML void sendText(){
        if(b.getText().equals("/System_exit")){
            Platform.exit();
        }else{
            try{
                DataOutputStream dout = Main.getDout();
                dout.writeUTF(Main.getUsername() + ": " + b.getText());
                b.setText("");
                dout.flush();
            }catch(Exception e){
                writeln("Failed to send message.");
                e.printStackTrace();
                b.setText("");
            }
        }
    }
}

chat_client.fxml 文件 (GUI):

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>

<VBox fx:controller="sample.Controller" alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" >
   <children>
      <TextArea id="textArea" fx:id="a" editable="false" prefHeight="350.0" prefWidth="580.0" VBox.vgrow="ALWAYS">
         <VBox.margin>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </VBox.margin>
      </TextArea>
      <HBox prefHeight="50.0">
         <children>
            <TextField fx:id="b" prefHeight="30.0" prefWidth="520.0">
               <padding>
                  <Insets left="10.0" right="10.0" />
               </padding>
            </TextField>
            <Region prefHeight="30.0" prefWidth="13.0" HBox.hgrow="ALWAYS" />
            <Button fx:id="c" onAction="#sendText" mnemonicParsing="false" text="Send" />
         </children>
         <padding>
            <Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
         </padding>
      </HBox>
   </children>
</VBox>

...当然,如果有一些方法可以改进我的代码,我想从我的错误中吸取教训;)

您在 ClientHandler 的 运行 方法中接受了两次客户端。

Socket s = ss.accept();
                if((s = ss.accept()) != null){

发生的事情是 ss.accept() 等待客户端连接。它连接,并继续到 if 语句。在这里您再次调用 ss.accept(),因此服务器再次等待直到客户端连接。第二个 ss.accept() 会阻止您的其余代码 运行ning。

解决方案:删除两个 ss.accept() 语句之一。示例:

if(s!=null){