gpt4 book ai didi

java - 简单的一种方式挂起线程

转载 作者:行者123 更新时间:2023-12-02 04:16:15 24 4
gpt4 key购买 nike

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

我所拥有的是,当有人发送请求时,监听器线程将客户端添加到 registerClients (其余内容超出了这个问题的范围)。

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

最初我认为这就像在 ListenerThread 中的 while 循环顶部使用 if 语句一样简单,该语句检查有多少客户端以及客户端计数是否小于零当客户端计数大约为零时,ListenerThread 将调用 heartbeatServer.heartbeatThread.wait()heartbeatServer.heartbeatThread.notify()。然而,当我这样做时,java 会抛出一个 IllegalMonitorException 。经过一番挖掘后,我发现异常是因为我没有在 synchronized block 内调用 wait()

由于我只想采用一种方式ListenerThread -> HeartbeatThread,而从不采用任何其他方式,我怎样才能实现这一目标?在每个线程中使用 synchronized block 是否会更好?如果是这种情况,那么我需要澄清一下我到底在同步什么。

我找到了这个例子;

boolean ready = false;

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


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

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

是否可以重新设计或完成该示例以满足我的需求,或者是否有更好的方法来解决我的问题?

我不太确定需要显示什么代码,以便我可以发布所请求的任何内容。

更新

我想我终于找到了解决问题的方法。 公共(public)类 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 的逻辑。

最佳答案

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

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

有一个论点说,当使用同步/等待/通知时,应该使用私有(private)最终对象而不是公开暴露的对象。争论的焦点是,如果锁对象被公开,那么其他代码本身可能会对其调用 wait/notify/synchronized 并导致难以追踪的副作用。无论如何,线程代码都很困难,因此争论的目的是减少外部干扰潜入的机会。这解释了您的示例,因为它遵循此约定。

关于java - 简单的一种方式挂起线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33282205/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com