在服务器端有一个后台线程定期更新请求使用的一些数据的最佳实践?
Best practices for having a background thread in Server side that periodically update some data used by request?
我有一个提供 REST API 的简单服务,我想在该服务中有一个后台线程,该线程定期运行以从远程服务检索一些数据并将数据更新到一个对象,该对象也被要求。
我的问题是在服务器端进行这种后台更新的最佳实践是什么?
为了获得最佳的并发性,我最初的想法是简单地在对象上使用 volatile
并在后台线程中重置此指针,因此所有请求都可以在更新后看到它并且可以请求查看旧版本对象的快照。这个实施有什么缺点吗? ReaderWriterLock 似乎是另一种选择,但对于这个来说太重了?
class Service
{
public volatile String data = "default";
public void handleRequest(Request req, Response resp)
{
resp.setBody(data);
}
}
class Background implements Runnable
{
private Service serv;
// ...
public void run()
{
serv.data = "reset to "+System.currentTimeMillis();
}
}
您的实施完全有效。 volatile 的主要目的是以线程安全的方式在线程之间共享引用。除了 volatile 语义 ReaderWriterLock
(和任何锁定)之外,还允许一起执行复合操作(原子的),而无需在线程之间交错。但是由于您没有任何应该一起执行的复合操作,因此在您的情况下,volatile(比锁定便宜)就足够了。
您还可以发现 Executors.newSingleThreadScheduledExecutor()
对安排后台任务很有用。
ScheduledExecutorService 满足您的要求。
/* You can set pool size depending on your requirement */
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(1);
您可以使用这两种方法中的一种。
ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
如果任务的任何执行遇到异常,则后续执行将被抑制。否则,任务只会通过取消或终止执行者来终止。如果此任务的任何执行时间超过其周期,则后续执行可能会延迟开始,但不会并发执行。
或
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next. If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor.
关于其他查询,ReentrantLock 是更好的选择。如果你正确地实现了锁定机制,你就不需要 volatile 变量。
查看此 article 了解其他高级并发控制。
我有一个提供 REST API 的简单服务,我想在该服务中有一个后台线程,该线程定期运行以从远程服务检索一些数据并将数据更新到一个对象,该对象也被要求。 我的问题是在服务器端进行这种后台更新的最佳实践是什么?
为了获得最佳的并发性,我最初的想法是简单地在对象上使用 volatile
并在后台线程中重置此指针,因此所有请求都可以在更新后看到它并且可以请求查看旧版本对象的快照。这个实施有什么缺点吗? ReaderWriterLock 似乎是另一种选择,但对于这个来说太重了?
class Service
{
public volatile String data = "default";
public void handleRequest(Request req, Response resp)
{
resp.setBody(data);
}
}
class Background implements Runnable
{
private Service serv;
// ...
public void run()
{
serv.data = "reset to "+System.currentTimeMillis();
}
}
您的实施完全有效。 volatile 的主要目的是以线程安全的方式在线程之间共享引用。除了 volatile 语义 ReaderWriterLock
(和任何锁定)之外,还允许一起执行复合操作(原子的),而无需在线程之间交错。但是由于您没有任何应该一起执行的复合操作,因此在您的情况下,volatile(比锁定便宜)就足够了。
您还可以发现 Executors.newSingleThreadScheduledExecutor()
对安排后台任务很有用。
ScheduledExecutorService 满足您的要求。
/* You can set pool size depending on your requirement */
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(1);
您可以使用这两种方法中的一种。
ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
如果任务的任何执行遇到异常,则后续执行将被抑制。否则,任务只会通过取消或终止执行者来终止。如果此任务的任何执行时间超过其周期,则后续执行可能会延迟开始,但不会并发执行。
或
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next. If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor.
关于其他查询,ReentrantLock 是更好的选择。如果你正确地实现了锁定机制,你就不需要 volatile 变量。
查看此 article 了解其他高级并发控制。