【问题标题】:Confusion with Synchronization and inter thread communication与同步和线程间通信混淆
【发布时间】:2021-03-17 18:31:27
【问题描述】:

我已经收到了这个问题,并且从几天以来我一直在尝试,但我无法获得正确的输出。任何帮助将不胜感激。

使用Send-Wait-Receive 协议在两个用户之间开发一个简单的聊天应用程序:

一旦用户发送消息,他会一直等待,直到收到来自其他用户的消息。用户是“User1”和“User2”。

在申请的初始阶段,User1 处于发送模式,User2 处于接收模式。这两个用户交替发送和接收消息。 - 使用两个方法创建一个 Chat 类:sendMessage 和 recvMessage - 创建两个线程来代表两个用户,User1 和 User2。 - 使用线程间通信来交换消息。 - 无需维护任何聊天记录。

输出:

用户1(用户2):你好

用户2(用户1):你好

用户2(用户1):你好

用户1(用户2):你好

class Chat{
    Scanner sc=new Scanner(System.in);
    String message;
    ArrayList<String> user1 = new ArrayList<String>();
    ArrayList<String> user2 = new ArrayList<String>();
    boolean sendMode = true;
    String name = "";
    String otherName = "";
    
    synchronized void recvMessage(){
        name = Thread.currentThread().getName();
        while(sendMode) {
            try{
                wait();
            }catch(InterruptedException e){
                System.out.println("InterruptedException caught");
            }
        }
        System.out.println(name);
        if (name.contentEquals("User1")) {
            otherName="User2";
        }
        else {
            otherName="User1";
        }
        System.out.println(name+"("+otherName+"):" + message);
        sendMode=true;
        System.out.println("rcv");
        notify();
    }
    
    synchronized void sendMessage(){
        name = Thread.currentThread().getName();
        while(!sendMode) {
            try{
                wait();
            }catch(InterruptedException e){
                System.out.println("InterruptedException caught");
            }
        }
        System.out.println(name);
        if (name.contentEquals("User1")) {
            otherName="User2";
        }
        else {
            otherName="User1";
        }
        System.out.print(name+"("+otherName+"):");
        message=sc.next();
        if(name.contains("User1")) {
            user1.add(message);
        }
        else {
            user2.add(message);
        }
        System.out.println("send");
        sendMode=false;
        notify();
    }
}

class Person1 implements Runnable{
    Chat ex;
    
    public Person1(Chat ex) {
        this.ex = ex;
        Thread u2=new Thread(this, "User1");
        u2.start();
    }
    
    public void run() {
        while(true) {
            ex.sendMessage();
        }
    }
}

class Person2 implements Runnable{
    Chat ex;
    
    public Person2(Chat ex) {
        this.ex=ex;
        Thread u1=new Thread(this, "User2");
        u1.start();
    }
    
    public void run() {
        while(true) {
            ex.recvMessage();
        }
    }
    
}

class Main{
    public static void main(String args[])
    {
        Chat ex =new Chat();
        new Person1(ex);
        new Person2(ex);
    }
} 

我得到的输出是: 用户1(用户2):嗨

用户2(用户1):嗨

用户2(用户1):你好

用户1(用户2):你好

User2(User1):怎么了

User1(User2): 是什么

用户2(用户1):用户1(用户2):向上

用户2(用户1):

基本上,线程并没有按顺序完成工作。前 4 行输出是正确的。但在那之后,总是 user2 发送消息,而 user1 接收它。

请帮帮我。

【问题讨论】:

    标签: java multithreading parallel-processing synchronization thread-safety


    【解决方案1】:

    您的代码有两个问题,首先是您正在使用:

     message=sc.next();
    

    而你应该使用:

     message=sc.nextLine();
    

    使用 next() 只会返回分隔符之前的内容 (默认为空格)。 nextLine() 自动移动扫描仪 返回当前行后向下。

    来自这个SO thread

    这就是为什么对于第一个没有空格的输入它可以正常工作,但是一旦你发送一个带空格的字符串:

    what's up
    

    你遇到了问题。

    第二部分是,在您当前的设计中,只有一个线程发送,另一个线程接收。为了让双方相互交流而不是独白,我建议这样做:

    class Chat{
        Scanner sc=new Scanner(System.in);
        String message;
        final Object rec = new Object();
        final Object send = new Object();
        boolean msg_send = false;
        boolean msg_recv = false;
    
        void recvMessage(){
            synchronized (send){
                while(!msg_send) {
                    try{
                        send.wait();
                    }catch(InterruptedException e){
                        System.out.println("InterruptedException caught");
                    }
                }
                msg_send = false;
            }
            synchronized (rec) {
                String name = Thread.currentThread().getName();
                System.out.println(name);
                String otherName = name.contentEquals("User1") ? "User2" : "User1";
                System.out.println(name + "(" + otherName + "):" + message);
                System.out.println("rcv");
                msg_recv = true;
                rec.notify();
            }
        }
    
         void sendMessage(){
             synchronized (send) {
                 String name = Thread.currentThread().getName();
                 System.out.println(name);
                 String otherName = name.contentEquals("User1") ? "User2" : "User1";
                 System.out.print(name + "(" + otherName + "):");
                 message = sc.nextLine();
                 System.out.println("send");
                 msg_send = true;
                 send.notify();
             }
            synchronized (rec) {
                while (!msg_recv) {
                     try {
                         rec.wait();
                     } catch (InterruptedException e) {
                         System.out.println("InterruptedException caught");
                     }
                 }
                 msg_recv = false;
            }
        }
    }
    
    class Person1 implements Runnable{
        Chat ex;
    
        public Person1(Chat ex) {
            this.ex = ex;
            Thread u2=new Thread(this, "User1");
            u2.start();
        }
    
        public void run() {
            while(true) {
                ex.sendMessage();
                ex.recvMessage();
            }
        }
    }
    
    class Person2 implements Runnable{
        Chat ex;
    
        public Person2(Chat ex) {
            this.ex=ex;
            Thread u1=new Thread(this, "User2");
            u1.start();
        }
    
        public void run() {
            while(true) {
                ex.recvMessage();
                ex.sendMessage();
            }
        }
    
    }
    
    class Main{
        public static void main(String args[])
        {
            Chat ex =new Chat();
            new Person1(ex);
            new Person2(ex);
        }
    } 
    

    使用表示消息何时接收和发送的两个对象进行等待和通知:

       final Object rec = new Object();
       final Object send = new Object();
    

    那么您需要了解何时应该在一个或另一个对象上同步的原因。

    【讨论】:

    • 谢谢。这也是一个问题,但主要问题是线程没有交替发送和接收消息。正如您在我的输出中看到的,首先 user1 将消息发送给 user2,然后 user2 接收它。接下来会发生相反的情况。但从第三次开始,总是 user2 向 user1 发送消息,而 user1 只是收到该消息。 user1 在第一次之后无法再发送消息。
    • 不。我不擅长线程间通信,但我知道它与 wait() 和 notify() 方法有关。代码的逻辑似乎是对的。
    • 好的,user1 必须向 user2 发送消息,user2 应该收到它(有发送和接收的方法)。然后 user2 应该向 user1 发送一条消息,而 user1 应该收到它。发送和接收应该在 user1 和 user2 之间交替进行,一次一个。这个问题现在清楚一点了吗??
    猜你喜欢
    • 1970-01-01
    • 2017-09-14
    • 2011-01-06
    • 2012-03-06
    • 1970-01-01
    • 2020-11-02
    • 2011-02-11
    • 2020-02-01
    • 1970-01-01
    相关资源
    最近更新 更多