正如我在标题中所写,我们需要在项目中通过另一个线程通知或执行一些线程的方法。此实现是长轮询的一部分。在下面的文字中描述并展示我的实施。
所以要求是: 当UserX得到之前的响应时,UserX立即从客户端向服务器发送请求(轮询操作)。在服务中执行spring async方法,如果数据库中有一些新数据,线程会立即检查缓存。我知道缓存通常用于特定输入是特定输出的方法。这不是那种情况,因为我使用缓存来减少数据库调用,并且我的方法的输出总是不同的。因此,如果我应该检查数据库,缓存可以帮助我存储通知。此检查在while循环中运行,当线程查找通知以读取缓存中的数据库或时间到期时结束。
假设UserX线程(轮询操作)当前处于while循环并检查缓存。
在那一刻UserY(推送动作)向服务器发送一些数据,数据以分离的线程存储在数据库中,并且缓存中也存储了收件人的userId。
因此,当UserX检查缓存时,他发现了收件人的id(收件人的ID ==在这种情况下他的id),然后中断循环并获取这些数据。
因此,在我的实现中,我使用google guava缓存来提供手动编写。
private static Cache<Long, Long> cache = CacheBuilder.newBuilder()
.maximumSize(100)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
在create方法中,我存储了应该读取这些数据的用户ID。
public void create(Data data) {
dataRepository.save(data);
cache.save(data.getRecipient(), null);
System.out.println("SAVED " + userId + " in " + Thread.currentThread().getName());
}
这是轮询数据的方法:
@Async
public CompletableFuture<List<Data>> pollData(Long previousMessageId, Long userId) throws InterruptedException {
// check db at first, if there are new data no need go to loop and waiting
List<Data> data = findRecent(dataId, userId));
data not found so jump to loop for some time
if (data.size() == 0) {
short c = 0;
while (c < 100) {
// check if some new data added or not, if yes break loop
if (cache.getIfPresent(userId) != null) {
break;
}
c++;
Thread.sleep(1000);
System.out.println("SEQUENCE: " + c + " in " + Thread.currentThread().getName());
}
// check database on the end of loop or after break from loop
data = findRecent(dataId, userId);
}
// clear data for that recipient and return result
cache.clear(userId);
return CompletableFuture.completedFuture(data);
}
用户X收到回复后,再次发送轮询请求,重复整个过程。
你能告诉我这个应用程序设计是否在java(spring)中进行长轮询是正确的还是存在更好的方法?关键点在于,当用户呼叫轮询请求时,该请求应该在一段时间内保留新数据,而不是立即响应。我在上面展示的这个解决方案有效,但问题是它是否也适用于许多用户(1000+)。我担心它是因为暂停线程,当池中没有线程可用时,应该使另一个请求变慢。感谢您的努力建议。
答案 0 :(得分:0)
检查Web套接字。 Spring在病房版本4上支持它。它不需要客户端启动轮询,而是服务器实时将数据推送到客户端。
检查以下内容:
https://spring.io/guides/gs/messaging-stomp-websocket/
http://www.baeldung.com/websockets-spring
注 - Web套接字在客户端和服务器之间打开持久连接,因此在大量用户的情况下可能导致更多的资源使用。因此,如果您不是在寻找实时更新,并且有一些延迟,那么轮询可能是更好的方法。此外,并非所有浏览器都支持Web套接字。
Web Sockets vs Interval Polling
In what situations would AJAX long/short polling be preferred over HTML5 WebSockets?
在您当前的方法中,如果您担心在服务器上为多个用户运行大量线程,那么您可以每次都从前端触发轮询。这样,只有短暂的请求线程才会从UI中触发,以查找缓存中的任何更新。如果有更新,则可以进行另一次调用以检索数据。但是,如果不这样做,请不要每隔一秒击中服务器,否则您的CPU利用率会很高,用户请求线程也会受到影响。你应该对你的时间做一些优化。
您可以通过分析一段时间内缓存/数据库更新的模式来应用智能算法,而不是在延迟1秒后缓存100次。
通过了解模式,您可以以指数退避方式触发轮询,以便在最有可能发生更新时命中缓存。这样,您将更频繁,更准确地访问缓存。