在Java中,两个线程都处于等待状态

在Java中,两个线程都处于等待状态,java,multithreading,synchronized,Java,Multithreading,Synchronized,我有一个服务器和两个客户机,服务器启动两个线程(ServerHandler),这两个线程都通过相应客户机的SocketTCP连接,这些客户机在开始时连接到服务器 预期行为: 一个ServerHandler线程向客户端发送消息,而另一个ServerHandler线程等待wait()。。。然后工作线程通知睡眠线程并等待。。。等等 实际行为: 两个服务器处理程序同时等待。它们都进入了synchronized块,而这种情况不应该发生,一个线程应该在等待,而另一个线程则在工作 服务器处理程序的代码片段(它

我有一个服务器和两个客户机,服务器启动两个线程(ServerHandler),这两个线程都通过相应客户机的
Socket
TCP连接,这些客户机在开始时连接到服务器

预期行为:
一个ServerHandler线程向客户端发送消息,而另一个ServerHandler线程等待
wait()
。。。然后工作线程通知睡眠线程并等待。。。等等

实际行为:
两个服务器处理程序同时等待。它们都进入了synchronized块,而这种情况不应该发生,一个线程应该在等待,而另一个线程则在工作

服务器处理程序的代码片段(它的两个实例正在运行)

private static Object lock = new Object();
...
@Override
public void run() {
    System.out.println(String.format("  --> Server handler: %s is in run method...", serverID));
    while (true) {
        synchronized (lock){
            while (!Server.isFinished()) {
                try {
                    System.out.println(String.format("  --> Server handler: %s is waiting...", serverID));
                    lock.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println(String.format("  --> Server handler: %s is ready to send board...", serverID));
            Server.setFinished(true);
            sendBoard();

            notify();
        }
    }
}
CLIENT connected!
<-- I'M Alan I want to play!
--> Server handler 1 instantiated!
CLIENT connected!
<-- I'M Bot I want to play!
--> Server handler 2 instantiated!
HANDLER started...
HANDLER started...
--> Server handler: 1 is in run method...
--> Server handler: 2 is in run method...
--> Server handler: 1 is waiting...
--> Server handler: 2 is waiting...
CLIENT connected!
<-- I'M Bot I want to play!
--> Server handler 1 instantiated!
CLIENT connected!
<-- I'M Alan I want to play!
--> Server handler 2 instantiated!
HANDLER started...
HANDLER started...
--> Server handler: 1 is in run method...
--> Server handler: 1 is waiting...
--> Server handler: 2 is in run method...
--> Server handler: 2 is ready to send board...
...
注意:
Server
类启动两个ServerHandler线程<默认情况下,代码>已完成设置为
false

输出:

private static Object lock = new Object();
...
@Override
public void run() {
    System.out.println(String.format("  --> Server handler: %s is in run method...", serverID));
    while (true) {
        synchronized (lock){
            while (!Server.isFinished()) {
                try {
                    System.out.println(String.format("  --> Server handler: %s is waiting...", serverID));
                    lock.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println(String.format("  --> Server handler: %s is ready to send board...", serverID));
            Server.setFinished(true);
            sendBoard();

            notify();
        }
    }
}
CLIENT connected!
<-- I'M Alan I want to play!
--> Server handler 1 instantiated!
CLIENT connected!
<-- I'M Bot I want to play!
--> Server handler 2 instantiated!
HANDLER started...
HANDLER started...
--> Server handler: 1 is in run method...
--> Server handler: 2 is in run method...
--> Server handler: 1 is waiting...
--> Server handler: 2 is waiting...
CLIENT connected!
<-- I'M Bot I want to play!
--> Server handler 1 instantiated!
CLIENT connected!
<-- I'M Alan I want to play!
--> Server handler 2 instantiated!
HANDLER started...
HANDLER started...
--> Server handler: 1 is in run method...
--> Server handler: 1 is waiting...
--> Server handler: 2 is in run method...
--> Server handler: 2 is ready to send board...
...
客户端已连接!
服务器处理程序2已实例化!
处理程序已启动。。。
处理程序已启动。。。
-->服务器处理程序:1正在运行方法。。。
-->服务器处理程序:2正在运行方法。。。
-->服务器处理程序:1正在等待。。。
-->服务器处理程序:2正在等待。。。
预期行为:

private static Object lock = new Object();
...
@Override
public void run() {
    System.out.println(String.format("  --> Server handler: %s is in run method...", serverID));
    while (true) {
        synchronized (lock){
            while (!Server.isFinished()) {
                try {
                    System.out.println(String.format("  --> Server handler: %s is waiting...", serverID));
                    lock.wait();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            System.out.println(String.format("  --> Server handler: %s is ready to send board...", serverID));
            Server.setFinished(true);
            sendBoard();

            notify();
        }
    }
}
CLIENT connected!
<-- I'M Alan I want to play!
--> Server handler 1 instantiated!
CLIENT connected!
<-- I'M Bot I want to play!
--> Server handler 2 instantiated!
HANDLER started...
HANDLER started...
--> Server handler: 1 is in run method...
--> Server handler: 2 is in run method...
--> Server handler: 1 is waiting...
--> Server handler: 2 is waiting...
CLIENT connected!
<-- I'M Bot I want to play!
--> Server handler 1 instantiated!
CLIENT connected!
<-- I'M Alan I want to play!
--> Server handler 2 instantiated!
HANDLER started...
HANDLER started...
--> Server handler: 1 is in run method...
--> Server handler: 1 is waiting...
--> Server handler: 2 is in run method...
--> Server handler: 2 is ready to send board...
...
客户端已连接!
服务器处理程序2已实例化!
处理程序已启动。。。
处理程序已启动。。。
-->服务器处理程序:1正在运行方法。。。
-->服务器处理程序:1正在等待。。。
-->服务器处理程序:2正在运行方法。。。
-->服务器处理程序:2已准备好发送板。。。
...

谢谢

你能举例说明你的预期产出吗

一个看起来像是意外错误的事情是两个线程都有自己的锁,而不是一个共享的锁(注意static

另一件没有意义的事情是调用您已经拥有的锁

private static Object lock=new Object();
公开募捐{
while(true){
已同步(锁定){
而(!Server.isFinished()){
试一试{
lock.wait();
}捕捉(中断异常e){
Thread.currentThread().interrupt();
}
}
setFinished(true);
发送板();
}
}
}

您能提供一些您预期输出的示例吗

一个看起来像是意外错误的事情是两个线程都有自己的锁,而不是一个共享的锁(注意static

另一件没有意义的事情是调用您已经拥有的锁

private static Object lock=new Object();
公开募捐{
while(true){
已同步(锁定){
而(!Server.isFinished()){
试一试{
lock.wait();
}捕捉(中断异常e){
Thread.currentThread().interrupt();
}
}
setFinished(true);
发送板();
}
}
}

不确定您在此处使用的同步机制是否正确

你的流程如下

  • 线程1抓取监视器
  • 线程1检查服务器状态
  • 服务器未就绪
  • 线程1丢弃监视器并等待
  • 线程2抓取监视器
  • 线程2检查服务器状态
  • 服务器未就绪
  • 线程2丢弃监视器并等待
  • 死锁,因为两个线程都在互相等待
  • 因此,线程永远无法通过服务器检查,因为没有人会通知它们可以继续。为了实现这一点,您需要线程1或线程2在两个线程都准备就绪时通知另一个线程,从而导致死锁

    您可能想考虑使用例如A。这将让您等待,直到您收集了足够的线程开始游戏

    private static Object lock = new Object();
    private static CyclicBarrier barrier = new CyclicBarrier(2, () -> setReady());
    ...
    @Override
    public void run() {
        System.out.println(String.format("  --> Server handler: %s is in run method...", serverID));
        while (true) {
            synchronized (lock){
                while (!Server.isFinished()) {
                    try {
                        System.out.println(String.format("  --> Server handler: %s is waiting...", serverID));
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
               }
               System.out.println(String.format("  --> Server handler: %s is ready to send board...", serverID));
    
                sendBoard();
    
                notify();
            }
        }
    }
    
    public static void setReady() {
        synchronized (lock) {
            try {
                sendBoard();
                System.out.println(String.format("  --> Server handler: %s is waiting...", serverID));
                lock.notify();
                lock.wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
    

    类似这样的方法可以让您更改块,直到两个线程都启动,第二个线程到达屏障,然后触发setReady方法发送电路板,然后再等待另一个线程。

    不确定您在这里使用的同步机制是否正确

    你的流程如下

  • 线程1抓取监视器
  • 线程1检查服务器状态
  • 服务器未就绪
  • 线程1丢弃监视器并等待
  • 线程2抓取监视器
  • 线程2检查服务器状态
  • 服务器未就绪
  • 线程2丢弃监视器并等待
  • 死锁,因为两个线程都在互相等待
  • 因此,线程永远无法通过服务器检查,因为没有人会通知它们可以继续。为了实现这一点,您需要线程1或线程2在两个线程都准备就绪时通知另一个线程,从而导致死锁

    您可能想考虑使用例如A。这将让您等待,直到您收集了足够的线程开始游戏

    private static Object lock = new Object();
    private static CyclicBarrier barrier = new CyclicBarrier(2, () -> setReady());
    ...
    @Override
    public void run() {
        System.out.println(String.format("  --> Server handler: %s is in run method...", serverID));
        while (true) {
            synchronized (lock){
                while (!Server.isFinished()) {
                    try {
                        System.out.println(String.format("  --> Server handler: %s is waiting...", serverID));
                        lock.wait();
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
               }
               System.out.println(String.format("  --> Server handler: %s is ready to send board...", serverID));
    
                sendBoard();
    
                notify();
            }
        }
    }
    
    public static void setReady() {
        synchronized (lock) {
            try {
                sendBoard();
                System.out.println(String.format("  --> Server handler: %s is waiting...", serverID));
                lock.notify();
                lock.wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }
    

    类似这样的东西可以让您更改块,直到两个线程都启动,第二个线程到达屏障,然后触发setReady方法,在等待另一个线程之前发送电路板。

    您必须在
    lock
    对象上调用
    notify

    您必须在
    lock
    对象上调用
    notify

    我编辑了我的问题(请参见预期行为)当我将它们锁定在静态对象上(如您所写)时,线程“thread-0”java.lang.IllegalMonitorStateException中的异常被抛出(在
    wait()
    语句中),您能再试一次吗?只有在对不拥有的锁调用
    wait()
    时才会引发异常。在这种情况下,
    lock.wait()
    synchronized(lock)
    块中被明确调用,因此必须为其所有。我尝试了5次,始终是一个非法监视器。。。例外情况您确定已将
    synchronized(此)
    更改为
    synchronized(锁定)
    ?更新:我忘了写