2017-09-13 42 views
1

我有一個提供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(); 
    } 
} 
+0

那麼,我會看看使用'java.util.Timer'而不是發明自己的。也許也看看crontab,雖然你的用例似乎並不支持這一點。 – markspace

回答

1

您的實施是完全有效的。 volatile的主要目的是以線程安全的方式正確共享線程之間的引用。除了易失性語義ReaderWriterLock(和任何鎖定)允許一起執行復合動作(原子),而不會在線程之間交錯。但是由於你沒有任何複合動作應該一起執行,揮發性(這比鎖定便宜)在你的情況下就足夠了。

您還可以找到Executors.newSingleThreadScheduledExecutor()用於安排您的後臺任務。

0

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) 

創建並執行一個給定的初始延遲之後第一啓用的定期操作,隨後與給定的週期;即執行將在initialDelay之後開始,然後是initialDelay +週期,然後是initialDelay + 2 *週期,依此類推。

如果任務的任何執行遇到異常,則後續執行被禁止。否則,任務將僅通過取消或終止執行者而終止。如果任務的執行時間比其週期長,則後續執行可能會晚點,但不會同時執行。

OR

ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, 
             long initialDelay, 
             long delay, 
             TimeUnit unit) 

與一個執行的終止和下一開始之間的給定的延遲創建並執行一個給定的初始延遲之後第一啓用的定期操作,並且隨後。如果任務的任何執行遇到異常,則後續執行被禁止。否則,任務將僅通過取消或終止執行者而終止。

關於其他查詢,ReentrantLock是更好的選擇。如果你正確地實現了鎖定機制,你將不需要volatile變量。

看看這個article其他高級併發控制。

相關問題