幾種實現延時任務的方式(二)

2021-09-11 14:59:51 字數 3122 閱讀 7654

在上一節中,我們講了三種方式來實現延時任務,其實,將三種方式結合起來用,對於一些中小型公司已經足夠了,但是在中大型網際網路公司還是遠遠不夠的。

想必大家對redis起碼有乙個初步的概念:基於記憶體的非關係型資料庫。在平時的業務開發中,redis經常會被用做快取,來提高**的效能,減少資料庫的訪問,所以一想到redis,腦海中第乙個浮現出來的就是快取。

沒辦法,對於搬磚業務開發,所使用到的redis基本也僅僅侷限於快取/代替session了。但是redis的應用場景很多很多。下面我就用redis來實現延時任務。

我在這裡假設大家已經對redis有了乙個基本的了解,並且使用過redis,所以我不再過多的講述redis的基本知識了。

##開門見山,我們會使用到redis的zset資料結構。

zset可以理解為set的公升級版本,set是無序的,zset是有序的,而且會實時排序,所以zset也被稱為 sort set,我是比較傾向於後面的稱呼的,因為從字面上的意思就可以知道這個set擁有乙個特點:排序。

zset有兩個元素:member ,score,zset會根據score進行排序,member就是成員的意思。

要想完成這個需求,我們第乙個想到的應該就是怎麼把資料推送給redis,第二個想到的是怎麼把redis資料給讀取出來。

我所用的是jedis

通過idea的自動提示功能,我們很容易找到zadd這方法,看起來推送資料給redis應該是這個方法:

讓我們試一下吧。

private static jedispoolconfig jedispoolconfig = null;

private static jedispool jedispool;

private static ******dateformat ******dateformat = new ******dateformat("yyyy/mm/dd hh:mm:ss");

static

private static void zadd(string key, string member, double score)

private static setzrangewithscores(string key, int start, int end)

private static void zrem(string key, string member)

複製**

在這裡我把ip和埠號,密碼,dbnum都給隱藏了 ,大家應該可以看懂。

我並沒有用spring或者是spring boot來管理redis,因為如果加上這些東西,還需要有spring或者spring boot的知識,而且這裡我僅僅是想演示下用redis實現延遲任務的乙個思路而已,基於此原因,大家也別糾結 沒有分不同的類,沒有異常處理 等等。

我們在main方法呼叫下zadd方法:

zadd("haha","order1",2018005130);

zadd("haha","order2",2017005130);

zadd("haha","order3",2016005130);

zadd("haha","order4",2021115130);

複製**

執行完成後,開啟redis管理工具,找到這個key,看一下結果:

score小的排前面,這也符合ordertime小的,越先過期。但是 score引數型別是double,所以我們不能把date型的ordertime直接放進去了,但是我們可以把date經過轉換,再放進去。

資料已經放進去了,怎麼拿出來呢?這個方法比較難找,只能借助於搜尋引擎了,最後確定了方法:

不管是引數,還是返回型別,都有點奇怪,難怪找不到。 我們呼叫下這個方法試一下。 根據引數名稱,猜測start是開始,end是結束,我們要讀取第乙個資料,應該是傳0,1,或者是1,2。但是 其實應該是傳0,0。。。真讓人沮喪。。返回的資料也很奇怪,看不懂啊:

這個先放一下,我們發現 這個資料雖然已經被讀取出來了,但是redis並麼有把這個資料刪掉。

讓我們想想,這個zset並不像delayqueue一樣,這個沒有延遲的功能。我們把資料推到redis,下一秒就可以讀出來。所以我們需要先把資料讀取出來,然後判斷這個訂單有沒有超時,如果沒有超時的話,sleep一段時間,再次判斷是否超時。超時了,則修改資料庫狀態,如果還是沒超時,繼續sleep,再判斷。所以上面讀取方法沒有刪除資料,是符合我們要求的。

我們需要找到刪除的方法,最後確定了方法:

這個方法比較簡單,就是乙個key,乙個可變的member。 我們呼叫下這個方法:

zrem("haha", "order3");

複製**

再看下redis的管理工具:

order3 被刪除了。

接下來的問題就是讀取資料方法那個奇怪的返回值怎麼使用了,也沒有什麼好的辦法,就是在執行的時候,alt+f8 調出視窗,各種嘗試唄。

下面,直接把最終**貼出來吧:

private static final int expiretime = 15000;

//其他略,上面有

public static void main(string args) catch (interruptedexception e)

produce(i);

}});

productthread.start();

thread consumthread = new thread(() -> );

consumthread.start();

}private static void produce(int orderid)

private static void consum

() else catch (interruptedexception e) }}

}}

複製**

最後讓我們執行一下:

沒有問題。

在這裡有兩個細節需要說明下:

這種實現方式其實也比較簡單,因為大家都或多或少的使用過redis,只要知道這幾個方法,很容易就可以實現。 但是相比上一節的三個方法來說,這個方法就高階很多了,支援多執行緒消費,支援多應用(部署)消費,應用伺服器宕機也沒事。

好了,到這裡,延時任務的第四種方式——使用redis 就講完了。

android 定時任務的幾種實現方式

android裡有時需要定時迴圈執行某段 或者需要在某個時間點執行某段 這個需求大家第一時間會想到timer物件,沒錯,不過我們還有更好的選擇。一 timer 實現定時任務 timer timer void oncreate timer new timer timer.schedule task,1...

PHP實現定時任務的幾種方式

關於定時任務,之前以前認識了一種最常用的 crontab定時任務。通過linux的定時任務去實現。今天又認識了一下php實現定時方式的其它方式,總結一下。伺服器定時任務,其實就是unix系統下的crontab實現,具體的設定 linux定時任務crontab 不過除了直接定時讀取php指令碼的方式,...

系統的定時任務和延時任務

注 當任務有輸出時,輸出會以郵件的形式傳送給at任務的發起者。步驟 開啟postfix服務 命令 內部命令 1.輸入數字是檢視指定郵件的具體資訊 2.headers是檢視郵件列表 3.help檢視內部命令幫助 4.q是退出檢視郵件 命令 注 如果不寫username,預設在當前使用者執行命令 步驟 ...