在线程之间使用同步集合

时间:2014-11-02 23:30:21

标签: java multithreading collections

代码 - > http://pastebin.com/1PFCGWQy

阻止我遇到

问题
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);
            }
        }

出于某种原因,我无法让它发挥作用。我已经在命令行环境中工作了,非常完美,但是我想将它移植到图形用户界面,这个问题让我感到困难的不止一小时。我不知道如何处理Client的原始类称为其他线程的事实,我需要发送和接收来自服务器的信息。

基本上,我的程序通过让客户端通过ServerSocket连接到服务器来工作,然后处理每个请求。当然,我刚刚在周四学习了套接字,但我想制作一个自己的程序......无论如何,继续,问题在于ServerClientFrontEnd类,由于某种原因,我不知道如何为我的生活,我用来获取输入文本的集合要么保持空白,要么就是不会从中读取。

也许它可能与我的while循环有关,但它之前完美无缺。我有一个TON的记录器到处记录所有东西,如果我在检查集合是否为空时添加一个else语句,它肯定会重复激活else语句,即使在给出一个值的synchronizedOutputCollection之后。事实上,我甚至在按下发送按钮时打印集合中的值。实际上,当我在线程内部尝试类似的print语句时,该集合为空并且保持为空。

如何在线程之间共享对象的同步集合?这个问题困扰着我,我真的很感激回复。

这也是可运行的,您只需要激活服务器和2个客户端来测试它。 P.S我尝试过BlockingQueues但它们会使GUI线程冻结,因为队列永远不会被读取,导致死锁。

1 个答案:

答案 0 :(得分:2)

正如@markspace在评论中指出的那样,你的代码中有很多有趣的东西。您应该向后退一步,返回命令行界面并重新编写整个类结构。删除这些内部类,使用客户端或服务器使用的某些接口(如MessageListenerConnectionListnener与其他类(如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);
}

当然我刚刚做了这个,但它只是一个例子,一旦你的类结构被正确分解,应该是它的东西将很容易挂钩。

列表可以继续但是底线是您需要仔细查看哪些类需要知道哪些信息和原因。拆分类并创建字段private,除非需要共享,否则不要共享信息!重要的是你真的要考虑减少code coupling


任何方式漫无目的地使用代码解决实际问题:在ServerClientFrontEnd.main中你有这个小贴士:

new ServerClientFrontEnd().startClient();

/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
    public void run() {
        new ServerClientFrontEnd().setVisible(true);
    }
});

您正在创建2个ServerClientFrontEnd实例,一个启动客户端,另一个启动显示GUI。显示GUI的那个是您更改字符串List而另一个列表始终为空的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);
    }
});