简体   繁体   English

如何在不获取java.lang.IllegalMonitorStateException的情况下更改在同步块中获取的锁,对其进行更改以及notifyAll()?

[英]how can I change the lock I have aquired in a synchronized block, change it, and notifyAll() without getting java.lang.IllegalMonitorStateException?

I know that questions have been asked about changing the lock in a synchronized block, but in my client side of multiThreaded socket programming I have a status enumeration in my class and every time I want to change it I get the lock and make the changes. 我知道有人问过有关在同步块中更改锁的问题,但是在多线程套接字编程的客户端中,我的类中有一个状态枚举,每当我想要更改它时,我都会得到锁并进行更改。 At the same time another thread is waiting (it also gets the same lock and after reaching the wait method lets go of it) to observe the changes after the changer thread makes its changes and calls notifyAll(). 同时,另一个线程正在等待(它也获得了相同的锁,并且在到达wait方法后放开了它)在更改程序线程进行更改并调用notifyAll()之后观察更改。 now if I want to notifyAll() on an object(i mean the state enum) which is changed I get java.lang.IllegalMonitorStateException! 现在,如果我想更改一个对象上的notifyAll()(我是指状态枚举),则会得到java.lang.IllegalMonitorStateException! I considered aquiring another shared final object as my lock but in this way maybe the threads still be able to manipulate state enum. 我考虑将另一个共享的最终对象用作我的锁,但是通过这种方式,线程可能仍然能够操纵状态枚举。 what is the best approach?? 最好的方法是什么? Any answer will be appreciated. 任何答案将不胜感激。 this is part of my code: 这是我的代码的一部分:

this is the changer thread: 这是转换器线程:

synchronized (client.getStatus()) {
    client.setStatus(ClientState.successfulRegistration);
    client.getStatus().notifyAll()
}

and this is the waiting thread: 这是等待的线程:

synchronized (client.getStatus()){
    try {
            client.getStatus().wait();
            System.out.println("signMeIn notified");
            ClientState result = client.getStatus();
            System.out.println(result);
            if(result.toString().equalsIgnoreCase("successfulSignIn") )
                //do sth
        } catch (InterruptedException e) {
            e.printStackTrace();
    }

There is an error in this code: 这段代码有错误:

synchronized (client.getStatus()) {
    client.setStatus(ClientState.successfulRegistration);
    client.getStatus().notifyAll()
}

You are only allowed to notifyAll() on an object you locked. 只允许您对锁定的对象进行notifyAll()。 But one line above you replaced the object with a different one. 但上方的一行用另一行替换了该对象。 It is a really bad idea to change a lock object. 更改锁对象是一个非常糟糕的主意。 Usually you will use "this" or you use a private object. 通常,您将使用“ this”或使用私有对象。

I would suggest the following solution: 我建议以下解决方案:

public synchronized void setStatus(T status) {}
public synchronized T getStatus() {}

The wait() and notifyAll() methods are only needed if you are waiting on a condition and want to release the lock. 仅当您正在等待条件并想释放锁时,才需要使用wait()和notifyAll()方法。 Here an example: 这里是一个例子:

public synchronized void add(T element) {
   while(full) {
     wait();
   }
   data.add(element);
   notifyAll();
}

public synchronized T remove() {
    while(empty) {
      wait();
    }
    T item = data.getAndremove();
    notifyAll();
    return item;
}

In this examples are many hidden concepts. 在此示例中,有许多隐藏的概念。 First you need a while-loop for the waiting. 首先,您需要一个while循环来等待。 Because if you wait and gets notified you are back in the ready-to-run-queue. 因为如果您等待并得到通知,您将返回准备运行队列。 But you do not know if the condition still holds so that you have to recheck the condition. 但是您不知道条件是否仍然成立,因此您必须重新检查条件。 This is why you use a while-loop instead of a if(). 这就是为什么您使用while循环而不是if()的原因。

The second concept is known by notify-and-resume. 第二个概念通过“通知并恢复”已知。 It is possible to notify() and keep the lock. 可以通知()并保持锁定状态。 So you do not have to put the notify() at the end. 因此,您不必将notify()放在最后。

The third concept is the difference between notify() and notifyAll(). 第三个概念是notify()和notifyAll()之间的区别。 The first one only wakes one thread. 第一个只唤醒一个线程。 If the data is empty and you wakes up a thread that wants to remove something so there would be a dead-lock. 如果数据为空,并且您唤醒了一个想要删除某些内容的线程,那么将导致死锁。 If you wake-up all, all will check if the condition is met and try to proceed. 如果您将全部唤醒,则所有人将检查条件是否满足并尝试继续。

Here an other example that matches more your code: 这是另一个匹配更多代码的示例:

public synchronized void doSth() {
   while(client.getStatus.equals("WAIT") {
        wait();
   }
   System.out.println("Status isn't wait");
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当我以静态方式同步块调用wait()时,为什么Java会抛出java.lang.IllegalMonitorStateException? - Why Java throw java.lang.IllegalMonitorStateException when I invoke wait() in static way synchronized block? notifyAll()方法上的java.lang.IllegalMonitorStateException - java.lang.IllegalMonitorStateException on notifyAll() method 从同步块中调用wait时发生java.lang.IllegalMonitorStateException - java.lang.IllegalMonitorStateException whilst calling wait from synchronized block baton.notifyAll给出java.lang.IllegalMonitorStateException尽管同步(蝙蝠) - baton.notifyAll gives java.lang.IllegalMonitorStateException despite synchronized(baton) 如何在main方法中调用wait()方法? 如果我使用它,它将给出java.lang.IllegalMonitorStateException - How do I invoke wait() method in main method? if I use it then it will give java.lang.IllegalMonitorStateException java.lang.IllegalMonitorStateException: 当前线程不是锁的所有者 - java.lang.IllegalMonitorStateException: Current thread is not owner of the lock 超时时发生java.lang.IllegalMonitorStateException - java.lang.IllegalMonitorStateException on timeout 当我添加 <mvc:annotation-driven /> ,出现“创建bean时出错”,“ java.lang.IllegalMonitorStateException” - When I add <mvc:annotation-driven />, I get a “Error creating bean”, “java.lang.IllegalMonitorStateException” 线程通信:如何发出信号,表明已单击某个键? java.lang.IllegalMonitorStateException - Thread communication: How to signal that a key was clicked? java.lang.IllegalMonitorStateException java.lang.IllegalMonitorStateException (java selenium) - java.lang.IllegalMonitorStateException (java selenium)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM