多线程不是 运行 并行
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){
我 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){