簡體   English   中英

Java Servlet-使用通用計時器阻止所有線程

[英]Java Servlets - block all threads using common timer

在Tomcat 6上,我正在運行一個servlet,該servlet接受請求並將這些請求傳遞到外部系統。


外部系統上有一個節流限制-如果請求的數量超過每秒一定數量,則外部系統將以Http 503進行響應。至少2秒鍾內沒有其他請求可以到達外部系統,否則外部系統將重新啟動其節流計時器。 最初,我檢測到503 HttpResponse並執行Thread.sleep(2000),但這是錯誤的,因為它不能阻止servlet使用其他線程處理其他請求-一旦檢測到503響應,我就需要在至少2秒。


理想情況下,我希望阻塞的線程不要同時喚醒所有線程,而是說間隔100毫秒,以便按順序處理請求。 我查看了Condition和ReentrantLock,但不確定是否合適。

只需在Servlet中創建一個全局(靜態)日期變量。 當您收到503時,將此變量從null更改為本地時間。 Servlet在聯系外部系統之前應始終檢查此變量。 如果變量為null,或者已超過2秒,則可以繼續。 否則,阻塞線程(或引發異常)。

看起來像是在給我打電話給Amazon服務,而且可以輕松地對其進行管理。

您需要一個集中的托管模塊來執行此操作,它就像一個模塊一樣。

重要的是,您根本不應達到throttling limitation ,並且如果收到過多的請求將達到此值,那么您應該稍后響應客戶端檢查結果(作為異步工作)。

如果請求是一項很重要的業務(例如收取款項),那么您也必須使用該模塊來實現故障轉移,只需將請求數據持久保存到數據庫中即可,因此,如果有任何失敗,您將獲得來自數據庫。

如果您熟悉MQ arch,那么這是為此類材料設計的最佳解決方案,但是您希望擁有自己的MQ,您可以接受並處理模塊管理調用所有調用外部系統的請求。

首先,您可能有一個實體類,其中包含請求信息,例如

class entity{public String id,srv,blah_blah;}

其次,一個用於接受和處理請求的獨立模塊,這也是請求的上下文。 喜歡以下

class business{private business(){}// fan of OOP? K, go for singleton
private static final ArrayList<entity> ctx=new ArrayList<entity>();
static public void accept_request(entity e){_persist(e);ctx.add(e);}
static private void _persist(entity e){/*persist it to the db*/}
static private void _done(entity e){_remove(e);/*informing 3rd. parties if any*/}
static private void _remove(entity e){/*remove it from the db, it's done*/}
final private static int do_work(e){/*do the real business*/return 0;}//0 as success, 1, fail, 2....
}

但這還沒有完成,現在您需要一種方法來調用do_work()家伙,所以我建議使用后台線程(也將是守護進程!)

因此客戶只需將請求推送到類似上下文的類,在這里我們需要線程,如下所示

class business{...
static public void accept_request(entity e){_persist(e);ctx.add(e);synchronized(ctx){ctx.notify();}}
...
private static final Runnable r=new Runnable(){public void run(){try{
  while(!Thread.currentThread().interrupt()){
    if(ctx.size()==0){synchronized(ctx){if(ctx.size()==0){ctx.wait();}}}
    while(ctx.size()>0){entity e=ctx.get(0);ctx.remove(0);
     if(do_work(e)==0){_done(e);}else{ctx.add(e);/*give him another chance maybe!*/}end-else
    Thread.Sleep(100/*appreciate sleep time*/);}//end-loop

  }
}catch(Throwable wt){/*catch signals, maybe death thread*/}}};
static private Thread t;
void static public start_module(){t=new Thread(r);t.start();}
void static public stop_module(){t.interrupt();t.stop();}
...}

提示:嘗試不要在容器初始化過程之外啟動線程(調用start_module() ),否則會發生內存泄漏! 最好的解決方案是通過servlet的init()方法調用線程,然后才調用此模塊,並且當然要通過應用程序暫停( destroy() )暫停線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM