怪我咯2017-04-18 10:41:26
個人覺得所有的軟體定時都是透過輪尋來完成的,而專門開一個執行緒來執行這樣的任務比較消耗資源,感覺下面的方案可能表現會好一些。
0.首先,我們需要一個每隔5分鐘發送一個廣播的「定時廣播」
1.當用戶註冊時,我們註冊一個監聽者去監聽「定時廣播」
2.如果用戶點擊郵箱中的激活地址,則將先前註冊的監聽者關閉
3.如果監聽者第二次收到廣播後,則執行任務,並取消監聽
之所以要在第二次收到廣播的時候執行任務,是為了確保定時在5~10分鐘後能執行任務。當然這樣做不能保證準確的定時時間,如果需要提高定時精度的話則可以每分鐘發一次廣播,甚至每秒鐘發一次廣播,但是該場景應該不太需要。
定時廣播的實現的話,可以使用quartz等工具,甚至可以用訊息隊列的方式來獨立這一業務。
希望可以有所幫助,如果有不合適和有錯誤的地方也請儘管拍磚
大家讲道理2017-04-18 10:41:26
使用spring的定時器在service層完成即可在資料庫中有一個欄位在註冊的時候為0註冊之後調用spring的定時器在五分鐘後每隔幾秒掃描資料庫中的這個欄位並且產生驗證碼使用者點擊了郵箱中的地址停止定時器我可以給你spring定時器的文檔和代碼
貼上一段jdk原生的定時器和觸發器 Timer 和 TimerTask 是重點 在timer調用schedule時註冊監聽 或 其他方法調用即可 更多 請參考JDK開發文檔 文檔中有詳細的說明。我的這個小Demo沒有取消任務.
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Demo {
public static void main(String[] args) {
Timer timer = new Timer();
Long long1 =new Long("1486308200000");
timer.schedule(new TaskDemo(), new Date(long1));
}
}
class TaskDemo extends TimerTask{
@Override
public void run() {
System.out.println("点前时间是"+new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
}
}
ringa_lee2017-04-18 10:41:26
這種一次性的定時器用訊息佇列去實作是比較適合的,實作的話是比較簡單的,都有成熟的方案,Java裡最不缺的就是輪子。訊息佇列如:RabbitMQ,ActiveMQ,RocketMQ
高洛峰2017-04-18 10:41:26
你這個設計有問題:
依照你的設計,每個使用者的註冊都要開啟一個定時任務,那麼如果有大量使用者註冊呢?定時任務其實就是一個線程,開啟大量線程會消耗太多CPU資源。
用戶點擊郵箱啟動地址,然後銷毀。如果你是將定時任務儲存在JVM內的話,在叢集部署的時候就會很可能失效,因為你無法保證使用者註冊和啟動時存取到的是同一個JVM實例。
定時任務發現使用者未激活,然後重新產生驗證碼。為何要在用戶下次點擊發送郵件之前就產生?
我認為比較好的設計應該是這樣的:
用戶註冊,用戶啟動狀態=否
用戶點擊【發送啟動郵件】,後台產生啟動url,url裡附帶一個uuid,這個uuid和用戶名相關聯,儲存起來(uuid、用戶名、過期時間),然後發送郵件
用戶點擊郵件中啟動url,訪問到你的應用程式
你的應用得到url中的uuid,看其在資料庫中是否存在、且還沒過期。如果yes,取得其關聯的用戶名,更新用戶啟動狀態=true,刪除掉這個uuid;如果no,就啥都不幹。
uuid的儲存:
可以儲存在資料庫裡,不過為了清理過期的數據,你可以另外單開一個(只需要一個)線程,每1分鐘去跑一次,將資料庫裡過期的uuid刪除。
也可以儲存在redis中,redis有一個特性,就是可以指定資料的ttl,到期了它會自動刪除的,這樣就用不著單開一個執行緒清理過期uuid了。