我有一个小项目,其中有2个线程ListenerThreadHeartbeatThread都是HeartbeatServer中的嵌套类。

我所拥有的是,当有人发送请求时,侦听器线程会将客户端添加到registerClients(其余内容不在此问题的范围之内)。

HeartbeatThread哈希图中没有客户端时,我正在寻找一种挂起registerClients的简单方法。

最初我想这很容易,就像在ListenerThread的while循环顶部使用if语句来检查有多少个客户端,如果客户端计数小于零,则ListenerThread会调用和heartbeatServer.heartbeatThread.wait()(当客户计数约为零时)。但是,当我这样做时,java会抛出一个heartbeatServer.heartbeatThread.notify()。经过一些挖掘后,我发现了异常是因为我没有在IllegalMonitorException块内调用wait()

既然我只想做一种方法synchronized,而从不做别的方法,我该怎么做呢?在每个线程中使用ListenerThread -> HeartbeatThread块还是更好吗?如果是这种情况,那么我需要澄清一下我正在同步的内容。

我找到了这个例子。

boolean ready = false;

// thread 1
synchronized(lock) {
    ready = true;
lock.notifyAll();
}


// thread 2
synchronized(lock) {
    while(!ready)
        lock.wait();
}


这个例子看起来可以解决我的问题。但是由于我是新手,所以我不确定synchronized应该是什么。

是否可以根据我的需要对示例进行重新设计或完成,或者有更好的方法来解决我的问题?

我不确定要显示什么代码,所以我可以张贴任何要求的内容。

更新

我想我终于解决了我的问题。
    公共类HeartbeatServer {

final Object lock = new Object();
volatile Boolean suspended = true;

//TEST USE ONLY
volatile int userCount = 0;

// This is the thread that will send the heartbeats back to the client.
private class HeartbeatThread implements Runnable {

    @Override
    public void run() {

        HeartbeatServer heartbeatServer = HeartbeatServer.getInstance();

        while (true) {

            synchronized (heartbeatServer.lock) {

                if(suspended) {

                    try {

                        System.out.println("Suspending heartbeat thread!");
                        heartbeatServer.lock.wait();

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                } else {

                    System.out.println("Resuming heartbeat thread!");

                } // End if block

            } // End synchronized block

            try {

                Thread.sleep(2000L);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        } // End while loop

    } // End run method

} // End HeartbeatThread

// This is the thread that will listen for clients connecting to the server.
private class ListenerThread implements Runnable {

    // The instance of heartbeatServer should be the first object so we can use it everywhere in the class.
    HeartbeatServer heartbeatServer = HeartbeatServer.getInstance();

    private void suspendHeartbeats() {

        synchronized (heartbeatServer.lock) {

            heartbeatServer.suspended = true;

        }

    } // End suspendHeartbeats

    private void resumeHeartbeats() {

        synchronized (heartbeatServer.lock) {

            heartbeatServer.suspended = false;
            heartbeatServer.lock.notify();

        }

    } // End resumeHeartbeats

    @Override
    public void run() {

        while(true) {

            if(heartbeatServer.userCount < 1) {

                suspendHeartbeats();

            } else {

                resumeHeartbeats();

            }

        } // End while loop

    } // End run method

} // End ListenerThread

} // End HeartbeatServer


还有什么我可以做以改善我的线程吗? HeartbeatThread中的某些部分是测试遗留的。但是我更多地提到了用于挂起HeartbeatThread的逻辑。

最佳答案

您听起来好像已经找到了所需的核心,这只是信心使您退缩了。在Java中,wait / notify是相当低级的原语,在使用它们时通常会潜伏着细微的计时错误。这就是为什么存在诸如ReadWriteLock,Semaphore等更高级别的抽象的原因。 Java API文档中有一个示例演示如何阻塞直到达到条件(例如空或满)here,他们已经使用ReentrantLock和Condition来指示空/不空。

回到关于锁对象的问题,这只是他们正在调用等待/通知的对象。只要它始终是同一对象,它就可以是或多或少的任何对象。

有一种说法认为,在使用synced / wait / notify时,应使用私有的最终对象而不是公开的对象。论据是,如果锁定对象被暴露,则其他代码本身可能会对其调用wait / notify / synchronized,并引起副作用,而这种副作用可能很难跟踪。无论如何,线程代码都是很难的,因此该论据旨在减少外部干扰蔓延的机会。这是对您的示例的解释,因为它遵循了这一约定。

07-26 05:14