gpt4 book ai didi

Java 执行器服务 :- Notify a thread to wake up when an event occurs

转载 作者:行者123 更新时间:2023-11-30 07:55:23 25 4
gpt4 key购买 nike

我有一个管理器类,多个线程将自己注册到该类(使用 UUID 为每个请求生成唯一标识符),提供要处理的有效负载并从管理器获得相应的响应。我正在使用 java.util.concurrent.ExecutorService 启动多个线程。这是用于测试我的管理器功能的实现 -

public class ManagerTest {
public static void main(String[] args) {
try {
Manager myManager = new Manager();
// Start listening to the messages from different threads
myManager.consumeMessages();
int num_threads = Integer.parseInt(args[0]);
ExecutorService executor = Executors.newFixedThreadPool(num_threads);

for (int i = 0; i < num_threads; i++) {
// class implementation is given below
Runnable worker = new MyRunnable(myManager);
executor.execute(worker);
}
executor.shutdown();
// Wait until all threads are finish
while (!executor.isTerminated()) {

}
System.out.println("\nFinished all threads");

myManager.closeConnection();

} catch (IOException | TimeoutException e) {
e.printStackTrace();
}
}
}

下面是MyRunnable类的实现

class MyRunnable implements Runnable {
private Manager managerObj;
public MyRunnable(Manager managerObj) {
this.managerObj = managerObj;
}

@Override
public void run() {
try {
Random rand = new Random();
int n = rand.nextInt(35);
String requestId = UUID.randomUUID().toString();
managerObj.registerRequest(requestId, n);
managerObj.publishMessage(requestId);
// Want to avoid this while loop
while( ! managerObj.getRequestStatus(requestId)){

}
int response = managerObj.getRequestResponse(requestId);
// do something else
managerObj.unregisterRequest(requestId);

} catch (IOException e) {
e.printStackTrace();
}
}
}

管理器将处理请求,并且根据负载的不同,请求的响应可能需要不同的时间。每当管理器获得响应时,它都会通过调用此函数 setRequestStatus(requestId) 将请求状态设置为 true。在此之后,线程将从 while 循环 中退出并继续执行。

如果代码工作正常,但线程正在做太多工作,然后需要不断循环 while 循环直到满足条件。

他们是在向管理器发送请求后让线程 hibernate 的一种方法,并且管理器向该线程发出信号以在其响应准备就绪时唤醒。

如果这对某些人来说太简单了,请原谅我,我是 Java 和 Java 线程接口(interface)的新手。

最佳答案

没关系,我们习惯了简单的问题,而你的问题其实写得很好并且有一个合理的问题要解决,我们每天都看到很多更糟糕的问题,比如人们不知道他们想要什么,如何提出要求等

所以,你正在做的是一个繁忙的自旋循环,这是一件非常糟糕的事情,因为 a) 它每个线程消耗了一个完整的 CPU 内核,并且 b) 它实际上让 CPU 保持忙碌,这意味着它正在从可能有有用工作要做的其他线程窃取处理时间。

有很多方法可以解决这个问题,我会从最差到最好列出它们。

  • 改进代码的最简单方法是调用 java.lang.Thread.sleep(long millis) 方法,将 0 作为参数传递给它.这也被称为“yield”操作,它本质上意味着“如果有任何其他线程有一些有用的工作要做,让它们运行,并在它们完成后返回给我”。这只比 busy-spin-looping 稍微好一点,因为它仍然会消耗 100% 的 CPU。好处是它只会消耗 CPU 而其他线程无事可做,所以至少不会减慢其他事情。

  • 下一个最好但仍然不是很聪明的改进代码的方法是调用 java.lang.Thread.sleep(long millis) 方法传递它 1 作为参数。这被称为“传递”操作,它本质上意味着“将我的时间片的剩余部分释放给可能有一些有用工作要做的任何其他线程”。换句话说,剩余的时间片被没收,即使整个系统不需要做任何有用的工作。这将使 CPU 消耗降低到几乎为零。缺点是 a) CPU 消耗实际上会略高于零,b) 机器将无法进入某种低功耗 sleep 模式,c) 您的工作线程的响应速度会稍慢:它会恢复仅在时间片边界上工作。

  • 解决问题的最佳方法是使用 java 内置的同步 机制,如以下答案所述:https://stackoverflow.com/a/5999146/773113这不仅会消耗零 CPU,甚至可以让机器在等待时进入低功耗模式。

  • 要解决最一般情况下的问题,您不希望只等到某个条件,而是实际上还传递有关已完成的工作或将要完成的工作的信息,您将使用 BlockingQueue。 ( https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html ) 阻塞队列使用 java 内置同步机制工作并且允许一个线程将信息传递给另一个线程。

关于Java 执行器服务 :- Notify a thread to wake up when an event occurs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43271626/

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