与同步和线程间通信混淆

68bkxrlz  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(370)

我被问到这个问题,我已经尝试了几天,但我不能得到正确的输出。任何帮助都将不胜感激。
使用开发两个用户之间的简单聊天应用程序 Send-Wait-Receive 协议:
一旦一个用户发送了一条消息,他就会等待,直到从另一个用户那里收到一条消息。用户是“user1”和“user2”。
在应用程序的初始阶段,user1处于发送模式,user2处于接收模式。这两个用户交替地发送和接收消息-创建一个有两个方法的聊天类:sendmessage和recvmessage-创建两个线程来表示两个用户user1和user2-使用线程间通信来交换消息-无需维护任何聊天记录。
输出:
用户1(用户2):嗨
用户2(用户1):嗨
user2(user1):你好
user1(user2):你好

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

我得到的输出是:user1(user2):嗨
用户2(用户1):嗨
user2(user1):你好
user1(user2):你好
user2(user1):怎么了
用户1(用户2):这是什么
用户2(用户1):用户1(用户2):向上
用户2(用户1):
基本上线程没有按顺序完成它们的工作。输出的前4行是正确的。但在那之后,总是user2发送消息,user1接收消息。
请帮帮我。

htzpubme

htzpubme1#

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

message=sc.next();

相反,你应该使用:

message=sc.nextLine();

使用next()只返回分隔符前面的内容(默认为空白)。nextline()返回当前行后自动向下移动扫描仪。
从这条线。
这就是为什么对于没有空格的第一个输入,它可以正常工作,但是只要您发送一个带有空格的字符串:

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();

然后您需要关于何时应该在一个或另一个对象上同步的原因。

相关问题