亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解Java中的防抖和節(jié)流

 更新時間:2022年08月07日 11:37:03   作者:天下沒有收費的bug  
防抖是將多次執(zhí)行變?yōu)橹付〞r間內(nèi)不在觸發(fā)之后,執(zhí)行一次。節(jié)流是將多次執(zhí)行變?yōu)橹付〞r間不論觸發(fā)多少次,時間一到就執(zhí)行一次。這篇文章來和大家聊聊Java中的防抖和節(jié)流,感興趣的可以了解一下

概念

防抖(debounce)

當持續(xù)觸發(fā)事件時,一定時間段內(nèi)沒有再觸發(fā)事件,事件處理函數(shù)才會執(zhí)行一次,如果設定時間到來之前,又觸發(fā)了事件,就重新開始延時。

  • 防抖,即如果短時間內(nèi)大量觸發(fā)同一事件,都會重置計時器,等到事件不觸發(fā)了,再等待規(guī)定的事件,才會執(zhí)行函數(shù)。而這整個過程就觸發(fā)了一次點贊函數(shù)到服務器。原理:設置一個定時器,設置在規(guī)定的時間后觸發(fā)事件處理,每次觸發(fā)事件都會重置計時器。
  • 舉例:很簡單的例子,就是如果你瘋狂的給朋友圈點贊再取消點贊,這個過程都會把計時器清空,等到你點累了不點了,等待0.5秒,才會觸發(fā)函數(shù),把你最終結果傳給服務器。
  • 問題1:那既然是這樣,讓前端做防抖不就好了嘛。答案是可以,但是會失去用戶體驗。本來有的用戶點贊就是為了玩,現(xiàn)在你前端直接提示操作太快~請歇會。用戶是不是就失去了樂趣,這一點還得參考QQ空間的點贊,雖然我不知道它是不是用了防抖,但是他把點贊,取消點贊做成了動畫,這樣每次用戶操作的時候,都會跳出執(zhí)行動畫,大大增加了用戶的體驗性。
  • 問題2:那么問題來了,在一定時間內(nèi),一直點擊,就會重置計時器。那要是點擊一天一夜,是不是他就不會在執(zhí)行了呢。理論上是這樣,但是人會累的嘛??偛荒芤恢睉?zhàn)斗是吧。所以人做不到,只能是機器、腳本來處理了,那也正好,防抖還能用來阻擋部分腳本攻擊。

節(jié)流(throttle)

當持續(xù)觸發(fā)事件時,保證在一定時間內(nèi)只調(diào)用一次事件處理函數(shù),意思就是說,假設一個用戶一直觸發(fā)這個函數(shù),且每次觸發(fā)小于既定值,函數(shù)節(jié)流會每隔這個時間調(diào)用一次。

想到這里,很多人就會想到一個作用,沒錯,就是防重復提交。但是這個業(yè)務時間比較難把控,所以還是建議用它來做一些無狀態(tài)的操作比較好。比如說:刷新排行榜,前端看似一直在點擊,其實后端為了防止接口崩掉,每1秒才執(zhí)行真正的一次刷新。

區(qū)別

防抖是將多次執(zhí)行變?yōu)橹付〞r間內(nèi)不在觸發(fā)之后,執(zhí)行一次。

節(jié)流是將多次執(zhí)行變?yōu)橹付〞r間不論觸發(fā)多少次,時間一到就執(zhí)行一次

Java實現(xiàn)

java實現(xiàn)防抖和節(jié)流的關鍵是Timer類和Runnable接口。

其中,Timer中關鍵方法cancel() 實現(xiàn)防抖 schedule() 實現(xiàn)節(jié)流。下面簡單介紹一下這兩個方法。

Timer##cancel():Timer.cancel() 被調(diào)用之后整個Timer 的 線程都會結束掉。

這就很好理解了,既然是做防抖,只要你在指定時間內(nèi)觸發(fā),我直接 cancel()掉,就是取消掉,不讓他執(zhí)行。

Timer##schedule():用戶調(diào)用 schedule() 方法后,要等待N秒的時間才可以第一次執(zhí)行 run() 方法。

這個N是我們根據(jù)業(yè)務評估出來的時間,作為參數(shù)傳進去。

防抖(debounce)

package com.example.test01.zhangch;

import java.util.Timer;
import java.util.TimerTask;

/**
 * @Author zhangch
 * @Description java 防抖
 * @Date 2022/8/4 18:18
 * @Version 1.0
 */
@SuppressWarnings("all")
public class DebounceTask {
    /**
     * 防抖實現(xiàn)關鍵類
     */
    private Timer timer;
    /**
     * 防抖時間:根據(jù)業(yè)務評估
     */
    private Long delay;
    /**
     * 開啟線程執(zhí)行任務
     */
    private Runnable runnable;

    public DebounceTask(Runnable runnable,  Long delay) {
        this.runnable = runnable;
        this.delay = delay;
    }

    /**
     *
     * @param runnable 要執(zhí)行的任務
     * @param delay 執(zhí)行時間
     * @return 初始化 DebounceTask 對象
     */
    public static DebounceTask build(Runnable runnable, Long delay){
        return new DebounceTask(runnable, delay);
    }

    //Timer類執(zhí)行:cancel()-->取消操作;schedule()-->執(zhí)行操作
    public void timerRun(){
        //如果有任務,則取消不執(zhí)行(防抖實現(xiàn)的關鍵)
        if(timer!=null){
            timer.cancel();
        }
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                //把 timer 設置為空,這樣下次判斷它就不會執(zhí)行了
                timer=null;
                //執(zhí)行 runnable 中的 run()方法
                runnable.run();
            }
        }, delay);
    }
}

防抖測試1

可以看到,測試中,我 1 毫秒請求一次,這樣的話,1秒內(nèi)都存在連續(xù)請求,防抖操作永遠不會執(zhí)行。

public static void main(String[] args){
    //構建對象,1000L: 1秒執(zhí)行-->1秒內(nèi)沒有請求,在執(zhí)行防抖操作
    DebounceTask task = DebounceTask.build(new Runnable() {
        @Override
        public void run() {
            System.out.println("防抖操作執(zhí)行了:do task: "+System.currentTimeMillis());
        }
    },1000L);
    long delay = 100;
    while (true){
        System.out.println("請求執(zhí)行:call task: "+System.currentTimeMillis());
        task.timerRun();
        try {
            //休眠1毫秒在請求
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

結果如我們所料:

Connected to the target VM, address: '127.0.0.1:5437', transport: 'socket'
請求執(zhí)行:call task: 1659609433021
請求執(zhí)行:call task: 1659609433138
請求執(zhí)行:call task: 1659609433243
請求執(zhí)行:call task: 1659609433350
請求執(zhí)行:call task: 1659609433462
請求執(zhí)行:call task: 1659609433572
請求執(zhí)行:call task: 1659609433681
請求執(zhí)行:call task: 1659609433787
請求執(zhí)行:call task: 1659609433893
請求執(zhí)行:call task: 1659609433999
請求執(zhí)行:call task: 1659609434106
請求執(zhí)行:call task: 1659609434215
請求執(zhí)行:call task: 1659609434321
請求執(zhí)行:call task: 1659609434425
請求執(zhí)行:call task: 1659609434534

防抖測試2

測試2中,我們在請求了2秒之后,讓主線程休息2秒,這個時候,防抖在1秒內(nèi)沒有在次觸發(fā),所以就會執(zhí)行一次防抖操作。

public static void main(String[] args){
    //構建對象,1000L:1秒執(zhí)行
    DebounceTask task = DebounceTask.build(new Runnable() {
        @Override
        public void run() {
            System.out.println("防抖操作執(zhí)行了:do task: "+System.currentTimeMillis());
        }
    },1000L);
    long delay = 100;
    long douDelay = 0;
    while (true){
        System.out.println("請求執(zhí)行:call task: "+System.currentTimeMillis());
        task.timerRun();
        douDelay = douDelay+100;
        try {
            //如果請求執(zhí)行了兩秒,我們讓他先休息兩秒,在接著請求
            if (douDelay == 2000){
                Thread.sleep(douDelay);
            }
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

結果如我們所料,防抖任務觸發(fā)了一次,休眠結束之后,請求就會在1毫秒內(nèi)連續(xù)觸發(fā),防抖也就不會在次觸發(fā)了。

請求執(zhí)行:call task: 1659609961816
請求執(zhí)行:call task: 1659609961924
請求執(zhí)行:call task: 1659609962031
請求執(zhí)行:call task: 1659609962138
請求執(zhí)行:call task: 1659609962245
請求執(zhí)行:call task: 1659609962353
防抖操作執(zhí)行了:do task: 1659609963355
請求執(zhí)行:call task: 1659609964464
請求執(zhí)行:call task: 1659609964569
請求執(zhí)行:call task: 1659609964678
請求執(zhí)行:call task: 1659609964784

防抖測試簡易版

簡易版:根據(jù)新手寫代碼習慣,對代碼寫法做了調(diào)整,但是不影響整體功能。這種寫法更加符合我這種新手小白的寫法。

public static void main(String[] args){
    //要執(zhí)行的任務,因為 Runnable 是接口,所以 new 對象的時候要實現(xiàn)它的 run方法
    Runnable runnable =  new Runnable() {
        @Override
        public void run() {
            //執(zhí)行打印,真實開發(fā)中,是這些我們的業(yè)務代碼。
            System.out.println("防抖操作執(zhí)行了:do task: "+System.currentTimeMillis());
        }
    };

    //runnable:要執(zhí)行的任務,通過參數(shù)傳遞進去。1000L:1秒執(zhí)行內(nèi)沒有請求,就執(zhí)行一次防抖操作
    DebounceTask task = DebounceTask.build(runnable,1000L);
    //請求持續(xù)時間
    long delay = 100;
    //休眠時間,為了讓防抖任務執(zhí)行
    long douDelay = 0;

    //while 死循環(huán),請求一直執(zhí)行
    while (true){
        System.out.println("請求執(zhí)行:call task: "+System.currentTimeMillis());
        //調(diào)用 DebounceTask 防抖類中的 timerRun() 方法, 執(zhí)行防抖任務
        task.timerRun();
        douDelay = douDelay+100;
        try {
            //如果請求執(zhí)行了兩秒,我們讓他先休息兩秒,在接著請求
            if (douDelay == 2000){
                Thread.sleep(douDelay);
            }
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

節(jié)流(throttle)

package com.example.test01.zhangch;

import java.util.Timer;
import java.util.TimerTask;

/**
 * @Author zhangch
 * @Description 節(jié)流
 * @Date 2022/8/6 15:41
 * @Version 1.0
 */
public class ThrottleTask {
    /**
     * 節(jié)流實現(xiàn)關鍵類
     */
    private Timer timer;
    private Long delay;
    private Runnable runnable;
    private boolean needWait=false;

    /**
     * 有參構造函數(shù)
     * @param runnable 要啟動的定時任務
     * @param delay 延遲時間
     */
    public ThrottleTask(Runnable runnable,  Long delay) {
        this.runnable = runnable;
        this.delay = delay;
        this.timer = new Timer();
    }

    /**
     * build 創(chuàng)建對象,相當于 ThrottleTask task = new ThrottleTask();
     * @param runnable 要執(zhí)行的節(jié)流任務
     * @param delay 延遲時間
     * @return ThrottleTask 對象
     */
    public static ThrottleTask build(Runnable runnable, Long delay){
        return new ThrottleTask(runnable, delay);
    }

    public void taskRun(){
        //如果 needWait 為 false,結果取反,表達式為 true。執(zhí)行 if 語句 
        if(!needWait){
            //設置為 true,這樣下次就不會再執(zhí)行
            needWait=true;
            //執(zhí)行節(jié)流方法
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    //執(zhí)行完成,設置為 false,讓下次操作再進入 if 語句中
                    needWait=false;
                    //開啟多線程執(zhí)行 run() 方法
                    runnable.run();
                }
            }, delay);
        }
    }
}

節(jié)流測試1

節(jié)流測試,每 2ms 請求一次,節(jié)流任務是每 1s 執(zhí)行一次。真實效果應該是 1s 內(nèi)前端發(fā)起了五次請求,但是后端只執(zhí)行了一次操作

public static void main(String[] args){
    //創(chuàng)建節(jié)流要執(zhí)行的對象,并把要執(zhí)行的任務傳入進去
    ThrottleTask task = ThrottleTask.build(new Runnable() {
        @Override
        public void run() {
            System.out.println("節(jié)流任務執(zhí)行:do task: "+System.currentTimeMillis());
        }
    },1000L);
    //while一直執(zhí)行,模擬前端用戶一直請求后端
    while (true){
        System.out.println("前端請求后端:call task: "+System.currentTimeMillis());
        task.taskRun();
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

結果如我們所料

前端請求后端:call task: 1659772459363
前端請求后端:call task: 1659772459574
前端請求后端:call task: 1659772459780
前端請求后端:call task: 1659772459995
前端請求后端:call task: 1659772460205
節(jié)流任務執(zhí)行:do task: 1659772460377
前端請求后端:call task: 1659772460409
前端請求后端:call task: 1659772460610
前端請求后端:call task: 1659772460812
前端請求后端:call task: 1659772461027
前端請求后端:call task: 1659772461230
節(jié)流任務執(zhí)行:do task: 1659772461417

彩蛋

idea 爆紅線了,強迫癥的我受不了,肯定要解決它

解決方法1

腦子第一時間冒出來的是 @SuppressWarnings("all") 注解,跟所有的警告說拜拜~瞬間就清爽了

解決方法2

算了,壓制警告總感覺是不負責任。總不能這樣草草了事,那就來直面這個爆紅。既然讓我用 ScheduledExecutorService ,那簡單,直接替換

public class ThrottleTask {
    /**
     * 節(jié)流實現(xiàn)關鍵類:
     */
    private ScheduledExecutorService timer;
    private Long delay;
    private Runnable runnable;
    private boolean needWait=false;

    /**
     * 有參構造函數(shù)
     * @param runnable 要啟動的定時任務
     * @param delay 延遲時間
     */
    public ThrottleTask(Runnable runnable,  Long delay) {
        this.runnable = runnable;
        this.delay = delay;
        this.timer = Executors.newSingleThreadScheduledExecutor();
    }

    /**
     * build 創(chuàng)建對象,相當于 ThrottleTask task = new ThrottleTask();
     * @param runnable 要執(zhí)行的節(jié)流任務
     * @param delay 延遲時間
     * @return ThrottleTask 對象
     */
    public static ThrottleTask build(Runnable runnable, Long delay){
        return new ThrottleTask(runnable, delay);
    }

    public void taskRun(){
        //如果 needWait 為 false,結果取反,表達式為 true。執(zhí)行 if 語句
        if(!needWait){
            //設置為 true,這樣下次就不會再執(zhí)行
            needWait=true;
            //執(zhí)行節(jié)流方法
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    //執(zhí)行完成,設置為 false,讓下次操作再進入 if 語句中
                    needWait=false;
                    //開啟多線程執(zhí)行 run() 方法
                    runnable.run();
                }
            }, delay,TimeUnit.MILLISECONDS);
        }
    }
}   

那么定時器 Timer 和 ScheduledThreadPoolExecutor 解決方案之間的主要區(qū)別是什么,我總結了三點...

  • 定時器對系統(tǒng)時鐘的變化敏感;ScheduledThreadPoolExecutor并不會。
  • 定時器只有一個執(zhí)行線程;ScheduledThreadPoolExecutor可以配置任意數(shù)量的線程。
  • TimerTask中拋出的運行時異常會殺死線程,因此后續(xù)的計劃任務不會繼續(xù)運行;使用ScheduledThreadExecutor–當前任務將被取消,但其余任務將繼續(xù)運行。

到此這篇關于詳解Java中的防抖和節(jié)流的文章就介紹到這了,更多相關Java防抖 節(jié)流內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java實現(xiàn)異步執(zhí)行的8種方式總結

    Java實現(xiàn)異步執(zhí)行的8種方式總結

    這篇文章主要給大家介紹了關于Java實現(xiàn)異步執(zhí)行的8種方式,異步編程不會阻塞程序的執(zhí)行,它將耗時的操作提交給后臺線程或其他執(zhí)行環(huán)境,并立即返回,使得程序可以繼續(xù)執(zhí)行其他任務,需要的朋友可以參考下
    2023-09-09
  • 使用jpa原生sql@Query操作增刪改查

    使用jpa原生sql@Query操作增刪改查

    這篇文章主要介紹了使用jpa原生sql@Query操作增刪改查,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Quartz作業(yè)調(diào)度基本使用詳解

    Quartz作業(yè)調(diào)度基本使用詳解

    這篇文章主要為大家介紹了Quartz作業(yè)調(diào)度基本使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • mybatis mybatis-plus-generator+clickhouse自動生成代碼案例詳解

    mybatis mybatis-plus-generator+clickhouse自動生成代碼案例詳解

    這篇文章主要介紹了mybatis mybatis-plus-generator+clickhouse自動生成代碼案例詳解,本篇文章通過簡要的案例,講解了該項技術的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • java基礎二叉搜索樹圖文詳解

    java基礎二叉搜索樹圖文詳解

    二叉樹是一種非常重要的數(shù)據(jù)結構,它同時具有數(shù)組和鏈表各自的特點,下面這篇文章主要給大家介紹了關于java基礎二叉搜索樹的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-03-03
  • java向微信服務號發(fā)送消息的完整步驟實例

    java向微信服務號發(fā)送消息的完整步驟實例

    這篇文章主要介紹了java向微信服務號發(fā)送消息的相關資料,包括申請測試號獲取appID/appsecret、關注公眾號獲取openID、配置消息模板及代碼實現(xiàn),需要的朋友可以參考下
    2025-06-06
  • JAVA解決在@autowired,@Resource注入為null的情況

    JAVA解決在@autowired,@Resource注入為null的情況

    這篇文章主要介紹了JAVA解決在@autowired,@Resource注入為null的情況,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • java控制臺實現(xiàn)學生信息管理系統(tǒng)

    java控制臺實現(xiàn)學生信息管理系統(tǒng)

    這篇文章主要為大家詳細介紹了java控制臺實現(xiàn)學生信息管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Spring?Boot+Vue實現(xiàn)Socket通知推送的完整步驟

    Spring?Boot+Vue實現(xiàn)Socket通知推送的完整步驟

    最近工作中涉及消息通知功能的開發(fā),所以下面這篇文章主要給大家介紹了關于Spring?Boot+Vue實現(xiàn)Socket通知推送的完整步驟,文中通過實例代碼以及圖文介紹的非常詳細,需要的朋友可以參考下
    2023-04-04
  • SpringCloud集成Sleuth和Zipkin的思路講解

    SpringCloud集成Sleuth和Zipkin的思路講解

    Zipkin 是 Twitter 的一個開源項目,它基于 Google Dapper 實現(xiàn),它致力于收集服務的定時數(shù)據(jù),以及解決微服務架構中的延遲問題,包括數(shù)據(jù)的收集、存儲、查找和展現(xiàn),這篇文章主要介紹了SpringCloud集成Sleuth和Zipkin,需要的朋友可以參考下
    2022-11-11

最新評論