Java 在线程之间使用同步集合
代码-> 我遇到问题的块Java 在线程之间使用同步集合,java,multithreading,collections,Java,Multithreading,Collections,代码-> 我遇到问题的块 class ClientSender implements Runnable { Socket server; ServerClientFrontEnd SCFE; public ClientSender(Socket server, ServerClientFrontEnd SCFE){ this.server = server; this.SCFE = SCFE;
class ClientSender implements Runnable {
Socket server;
ServerClientFrontEnd SCFE;
public ClientSender(Socket server, ServerClientFrontEnd SCFE){
this.server = server;
this.SCFE = SCFE;
}
public void run(){
try(ObjectOutputStream out = new ObjectOutputStream(server.getOutputStream())){
//System.out.println("Client chat ver. 0.1");
//Scanner get = new Scanner(System.in);
while(!server.isClosed()){
//System.out.print("YOU:");
if(!SCFE.synchronizedOutputCollection.isEmpty()) // Here
{
logger.info("Has made it to ClientSender!");
String string = SCFE.synchronizedOutputCollection.firstElement();
logger.info(string);
out.writeObject(string); // Here
logger.info("Output Queue: " + SCFE.synchronizedOutputCollection.toString());
}
//else{ logger.info("It failed the conditional"); }
}
} catch (IOException ex) {
//logger.info("Closing connection...");
//System.exit(0);
}
}
}
class ClientReceiver implements Runnable {
Socket server;
ServerClientFrontEnd SCFE;
public ClientReceiver(Socket server, ServerClientFrontEnd SCFE){
this.server = server;
this.SCFE = SCFE;
}
public void run(){
try(ObjectInputStream in = new ObjectInputStream(server.getInputStream())){
while(!server.isClosed()){
SCFE.ChatBox.setText(SCFE.ChatBox.getText() + "\nOTHER: " + (String) in.readObject()); //Here
logger.info("Receiver has read object!");
}
} catch (IOException ex) {
logger.info("Closing connection");
System.exit(0);
} catch (ClassNotFoundException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
由于某种原因,我不能让它工作。我已经让它在命令行环境中工作,非常完美,但我想将它移植到图形用户界面,这个问题已经困扰了我一个多小时。我不知道如何处理客户机的原始类调用其他线程这一事实,我需要这些线程向服务器发送和接收信息
基本上,我的程序的工作原理是让客户端通过ServerSocket连接到服务器,然后ServerSocket处理每个请求。当然,我最近刚刚在周四学习了套接字,但我想做一个自己的程序。。。无论如何,接下来的问题是ServerClientFrontEnd类,出于某种原因,我不知道如何使用我的一生,我用来获取输入文本的集合要么保持为空,要么就是无法从中读取
也许这与我的while循环有关,但它以前工作得很好。我到处都有大量的记录器来记录一切,如果在检查集合是否为空时添加else语句,它肯定会反复激活else语句,即使在synchronizedOutputCollection被赋予一个值之后也是如此。事实上,我甚至在按下send按钮时打印集合内部的值。事实上,当我在线程中尝试一个类似的print语句时,集合是空的,并且仍然是空的
如何在线程之间共享对象的同步集合?这个问题困扰着我,我非常感谢你的回答
这也是可运行的,您只需激活服务器和2个客户端即可进行测试。另外,我尝试过阻止队列,但它们会使GUI线程冻结,因为从来没有读取队列,从而导致死锁。
正如@markspace在一篇评论中指出的,您的代码中有很多有趣的事情。您应该后退一步,回到命令行界面,重新设计整个类结构。删除这些内部类,使用一些接口,如
MessageListener
或connectionlistener
,您的客户端或服务器使用这些接口与其他类(如GUI)讨论收到的消息或创建/丢失的连接等问题
完成后,客户端的主要方法应该非常简单:
public static void main(String [] args) {
Client client = new Client("127.0.0.1");
client.addMessageListener(new MessageListener() {
public void messageRecieved(String message) {
System.out.println(message);
}
});
client.connect();
System.out.println("Connected to server.");
Scanner scanner = new Scanner(System.in);
String userInput = null;
boolean quit = false;
do {
userInput = scanner.readLine();
if(userInput != null && userInput.equals("quit")) {
client.sendMessage(userInput);
} else {
quit = true;
}
} while(!quit);
}
当然,这是我刚刚编出来的,但这只是一个例子,一旦你的类结构得到了正确的分解,它们应该在哪里,就很容易连接到GUI
这个列表可以继续下去,但底线是你需要仔细看看什么类需要知道什么信息以及为什么。将类分开,将字段设置为私有,除非需要共享,否则不要共享信息!重要的是你真的要考虑减少
在
ServerClientFrontEnd.main
中,您有一个snipplet:
new ServerClientFrontEnd().startClient();
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new ServerClientFrontEnd().setVisible(true);
}
});
您正在创建两个ServerClientFrontEnd
实例,一个启动客户端,另一个显示GUI。显示GUI的是更改字符串的列表
,而另一个列表始终为空。要使其工作,请将snipplet更改为:
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
ServerClientFrontEnd fontEnd = new ServerClientFrontEnd();
fontEnd.startClient();
fontEnd.setVisible(true);
}
});
嗯,不。创建一个(或者称为)并粘贴到这里。我不会在整个项目中寻找逻辑错误。我为我遇到问题的两个线程添加了一个代码块,并在出现问题的感兴趣区域之外添加了注释。我不认为我可以做一个SSCCE,因为它就是不工作,我不知道如何让它工作,即使我修剪了代码。“我不能让它工作”不是一个问题描述。你的代码真的很愚蠢。您有一个客户端和一个服务器,但它们都共享同一个GUI对象(ServerClientFrontEnd)。此外,您似乎正在从所有线程、客户端和服务器访问JFrame(同样是ServerClientFrontEnd)。那不行。