Java 分布式系统中的非法状态监视器异常

Java 分布式系统中的非法状态监视器异常,java,distributed-computing,Java,Distributed Computing,这是我的密码。它应该实现一种在分布式系统中同步调用的方法。这是我发送消息并等待确认的部分。网络和对等点应该是可靠的 但我的问题与本地同步有关,因为它不断引发此异常,我无法理解原因 Exception in thread "Thread-7" java.lang.IllegalMonitorStateException at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Object.java:503) at distr

这是我的密码。它应该实现一种在分布式系统中同步调用的方法。这是我发送消息并等待确认的部分。网络和对等点应该是可靠的

但我的问题与本地同步有关,因为它不断引发此异常,我无法理解原因

Exception in thread "Thread-7" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at distributed.PeerManager.sendAllWithAck(PeerManager.java:212)
at distributed.TokenManager.onTokenReceived(TokenManager.java:67)
at communication.TokenMessage.execute(TokenMessage.java:21)
at distributed.ListenThread.run(ListenThread.java:38)
Exception in thread "Thread-8" java.lang.IllegalMonitorStateException
    at java.lang.Object.notify(Native Method)
    at distributed.AckWaiter.run(AckWaiter.java:74)
下面是AckWater课程:

public class AckWaiter extends Thread {
    public int counter;
    PeerManager pm;
    Message m;
    public Object waiter;
    public int parentPort;

    public AckWaiter(PeerManager pm, Message m, int n,int parentPort) {
        counter = n;
        this.pm = pm;
        this.m = m;
        this.parentPort=parentPort;
        waiter=new Object();
    }

    public synchronized void notifyAck() {
        counter--;
            notify();

    }

    @Override
    public synchronized void run(){
        pm.sendAllExceptMe(m);

        try {
            BufferedReader inFromClient=new BufferedReader(new
                    InputStreamReader(pm.listener.socketMap.get(parentPort).getInputStream()));
            while(counter>0){
                    wait(100);
                    Message m=CustomMarshaller.getCustomMarshaller().unmarshal(inFromClient.readLine());
                    if(m==null){
                        continue;
                    }
                    m.execute(pm);
                }
                } catch (IOException | InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } 


        waiter.notify();
        return;
    }
}
这是应该阻止线程的调用

public synchronized void sendAllWithAck(Message m){
    if(aw!=null){
        throw new RuntimeException();
    }
    aw=new AckWaiter(this,m,connectionList.size()-1,m.sender.getPort());
    aw.start();
    try {
        aw.waiter.wait();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    aw=null;
}
“sendAllWithAck”应启动AckWater线程,等待对象“Water”,当我收到“n”个Ack时将收到通知

当接收到ACK消息时,通信层调用“notifyAck”方法

AckWater本身就是一个线程,因为负责从套接字读取数据的线程可以调用“sendAllWithAck”。我有n个对等点,每个对等点都有一个开放的套接字(有一个线程处理入站消息),用于其他对等点,因此如果我等待ACK响应收到的消息,我将无法从该对等点读取ACK(parentPort是该对等点的标识符,因此我可以定期检查该线程内的ACK)


如果此异常是由于结构问题引起的,我愿意修改我的体系结构,但我不知道在不修改通信层的情况下如何以不同的方式处理它,这将是一件痛苦的事情。

方法
wait()
notify()
notifyAll()
必须在
同步的
块中。而run方法仅由一个线程访问(因此不需要同步),并且ListenThread中存在异常。

它们都在同步方法中。在notify/wait时,您不同步您的
服务员
。你在你的对象上同步,这就是
synchonized
关键字的意思。我知道同步是如何工作的,但仍然不明白为什么这很重要。我必须等待两个不同的对象,因为一个是“等待直到收到一个ack,以便我可以评估剩下的ack数量”,另一个是,当我等待“服务员”时,意味着“等待直到我收到所有ack”,只需检查哪个对象是同步的,如果需要,更改为一个完成所有同步的对象。如果stackTrace不可理解,请使用调试器。@如果您不知道它是如何工作的。给自己找一本好书(实践中的并发性是最好的读物),你可能会对你的具体问题感兴趣。