Rumah > Java > javaTutorial > Bagaimana untuk melaksanakan anti goncang dan pendikit di Jawa

Bagaimana untuk melaksanakan anti goncang dan pendikit di Jawa

WBOY
Lepaskan: 2023-05-12 20:34:04
ke hadapan
1213 orang telah melayarinya

Konsep

Debounce

Apabila peristiwa dicetuskan secara berterusan, dan tiada peristiwa dicetuskan lagi dalam tempoh masa tertentu, fungsi pemprosesan acara akan dilaksanakan sekali tidak dicetuskan sebelum masa yang ditetapkan, , acara dicetuskan semula dan kelewatan bermula semula.

  • Anti-goncang, iaitu, jika sebilangan besar peristiwa yang sama dicetuskan dalam tempoh yang singkat, pemasa akan ditetapkan semula Fungsi tidak akan dilaksanakan sehingga acara tidak lagi dicetuskan, dan kemudian menunggu acara yang ditentukan. Dan keseluruhan proses ini mencetuskan fungsi serupa kepada pelayan. Prinsip: Tetapkan pemasa dan cetuskan pemprosesan acara selepas masa yang ditentukan Pemasa akan ditetapkan semula setiap kali peristiwa dicetuskan.

  • Contoh: Contoh yang sangat mudah ialah jika anda menyukai kalangan rakan anda seperti orang gila dan kemudian membatalkan suka, proses ini akan mengosongkan pemasa, dan anda akan berhenti mengklik apabila anda letih . Tunggu 0.5 saat sebelum fungsi dicetuskan dan hasil akhir anda dihantar ke pelayan.

  • Soalan 1: Jika begitu, bukankah lebih baik membiarkan bahagian hadapan melakukan anti goncang? Jawapannya ya, tetapi pengalaman pengguna akan hilang. Pada asalnya, sesetengah pengguna menyukainya hanya untuk bermain, tetapi kini bahagian hadapan anda terus menggesa anda bahawa operasi itu terlalu pantas ~ sila berehat. Sama ada pengguna telah kehilangan keseronokan mereka, perkara ini juga perlu merujuk kepada suka ruang QQ Walaupun saya tidak tahu sama ada ia menggunakan anti-goncang, ia mempunyai suka dan pembatalan animasi, supaya setiap kali pengguna beroperasi Semasa menjalankan, pelaksanaan. animasi akan muncul, yang sangat meningkatkan pengalaman pengguna.

  • Soalan 2: Kemudian inilah masalahnya Jika anda terus mengklik dalam tempoh masa tertentu, pemasa akan ditetapkan semula. Kemudian jika dia mengklik untuk satu hari satu malam, adakah dia akan berhenti melaksanakannya? Secara teori, ini benar, tetapi orang akan letih. Anda tidak boleh terus berjuang, bukan? Jadi manusia tidak boleh melakukannya, jadi mesin dan skrip hanya boleh mengendalikannya. Anti-goncang juga boleh digunakan untuk menyekat beberapa serangan skrip.

Pendikit

Apabila acara dicetuskan secara berterusan, ia dijamin hanya memanggil fungsi pemprosesan acara sekali dalam tempoh masa tertentu Ini bermakna dengan andaian pengguna terus mencetuskan Fungsi ini, dan setiap kali pencetus kurang daripada nilai yang ditetapkan, pendikitan fungsi akan dipanggil sekali setiap kali ini.

Memikirkan perkara ini, ramai orang akan memikirkan fungsi, ya, ia adalah untuk mengelakkan penyerahan berulang. Walau bagaimanapun, masa perniagaan ini sukar dikawal, jadi disyorkan untuk menggunakannya untuk melakukan beberapa operasi tanpa negara. Sebagai contoh: apabila menyegarkan kedudukan, bahagian hadapan seolah-olah mengklik sepanjang masa Malah, untuk mengelakkan antara muka daripada ranap, bahagian belakang hanya melakukan penyegaran sebenar setiap 1 saat.

Perbezaannya

Anti-goncang ialah menukar berbilang pelaksanaan kepada satu pelaksanaan selepas dicetuskan dalam masa yang ditetapkan.

Pendikitan adalah untuk menukar berbilang pelaksanaan kepada masa yang ditentukan Tidak kira berapa kali ia dicetuskan, ia akan dilaksanakan sekali apabila masanya tamat >Java pelaksanaan anti-goncang dan pendikit Kuncinya ialah kelas Pemasa dan antara muka Boleh Dijalankan.

Antaranya, kaedah utama cancel() dalam Pemasa melaksanakan anti goncang dan jadual() melaksanakan pendikit. Di bawah adalah pengenalan ringkas kepada kedua-dua kaedah ini.

Pemasa##cancel(): Selepas

Timer.cancel() dipanggil, keseluruhan urutan Pemasa akan tamat.

Ini mudah difahami Memandangkan ia anti goncang, selagi anda mencetuskannya dalam masa yang ditetapkan, saya akan terus membatalkan()nya, iaitu membatalkannya dan tidak membiarkannya dilaksanakan.

Pemasa##schedule():

Selepas pengguna memanggil kaedah schedule(), dia perlu menunggu N saat sebelum melaksanakan kaedah run() buat kali pertama.

N ini ialah masa kami menilai berdasarkan perniagaan dan diluluskan sebagai parameter. Anti goncang (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 {
    /**
     * 防抖实现关键类
     */
    private Timer timer;
    /**
     * 防抖时间:根据业务评估
     */
    private Long delay;
    /**
     * 开启线程执行任务
     */
    private Runnable runnable;

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

    /**
     *
     * @param runnable 要执行的任务
     * @param delay 执行时间
     * @return 初始化 DebounceTask 对象
     */
    public static DebounceTask build(Runnable runnable, Long delay){
        return new DebounceTask(runnable, delay);
    }

    //Timer类执行:cancel()-->取消操作;schedule()-->执行操作
    public void timerRun(){
        //如果有任务,则取消不执行(防抖实现的关键)
        if(timer!=null){
            timer.cancel();
        }
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                //把 timer 设置为空,这样下次判断它就不会执行了
                timer=null;
                //执行 runnable 中的 run()方法
                runnable.run();
            }
        }, delay);
    }
}
Salin selepas log masuk

Ujian anti goncang 1

Seperti yang anda lihat, semasa ujian, saya meminta sekali setiap 1 milisaat. akan ada kesinambungan dalam masa 1 saat Diminta, operasi anti-goncang tidak pernah dilakukan.

public static void main(String[] args){
    //构建对象,1000L: 1秒执行-->1秒内没有请求,在执行防抖操作
    DebounceTask task = DebounceTask.build(new Runnable() {
        @Override
        public void run() {
            System.out.println("防抖操作执行了:do task: "+System.currentTimeMillis());
        }
    },1000L);
    long delay = 100;
    while (true){
        System.out.println("请求执行:call task: "+System.currentTimeMillis());
        task.timerRun();
        try {
            //休眠1毫秒在请求
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Salin selepas log masuk

Hasilnya adalah seperti yang kami jangkakan:

Disambungkan ke VM sasaran, alamat: '127.0.0.1:5437', pengangkutan: 'soket'

Permintaan pelaksanaan: panggilan tugasan: 1659609433021

Permintaan pelaksanaan: panggilan tugas: 1659609433138
Permintaan pelaksanaan: minta panggilan tugas: 1659609433243

Permintaan pelaksanaan: panggilan tugasan: 14639 1659609433462
Permintaan pelaksanaan: tugasan panggilan: 1659609433572
Permintaan pelaksanaan: panggilan tugas: 1659609433681
Permintaan pelaksanaan: permintaan panggilan: 1659609433787
Permintaan pelaksanaan: panggilan tugasan: 14639 1659609433999
Permintaan pelaksanaan: tugasan panggilan: 1659609434106
Permintaan pelaksanaan: panggilan tugas: 1659609434215
Permintaan pelaksanaan: Permintaan tugasan: 1659609434321
Permintaan pelaksanaan: panggilan tugasan: 14659:14659 1659609434534


Ujian Anti-Shake 2

Dalam Ujian 2, selepas meminta selama 2 saat, kami biarkan benang utama berehat selama 2 saat Pada masa ini, anti-goncang tidak dicetuskan lagi dalam masa 1 saat, jadi ia akan dilaksanakan sekali.

public static void main(String[] args){
    //构建对象,1000L:1秒执行
    DebounceTask task = DebounceTask.build(new Runnable() {
        @Override
        public void run() {
            System.out.println("防抖操作执行了:do task: "+System.currentTimeMillis());
        }
    },1000L);
    long delay = 100;
    long douDelay = 0;
    while (true){
        System.out.println("请求执行:call task: "+System.currentTimeMillis());
        task.timerRun();
        douDelay = douDelay+100;
        try {
            //如果请求执行了两秒,我们让他先休息两秒,在接着请求
            if (douDelay == 2000){
                Thread.sleep(douDelay);
            }
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Salin selepas log masuk

Hasilnya adalah seperti yang dijangkakan Tugas anti-goncang dicetuskan sekali Selepas tidur selesai, permintaan akan dicetuskan secara berterusan dalam masa 1 milisaat, dan anti-goncang tidak akan dicetuskan lagi.

请求执行:call task: 1659609961816
请求执行:call task: 1659609961924
请求执行:call task: 1659609962031
请求执行:call task: 1659609962138
请求执行:call task: 1659609962245
请求执行:call task: 1659609962353
防抖操作执行了:do task: 1659609963355
请求执行:call task: 1659609964464
请求执行:call task: 1659609964569
请求执行:call task: 1659609964678
请求执行:call task: 1659609964784

防抖测试简易版

简易版:根据新手写代码习惯,对代码写法做了调整,但是不影响整体功能。这种写法更加符合我这种新手小白的写法。

public static void main(String[] args){
    //要执行的任务,因为 Runnable 是接口,所以 new 对象的时候要实现它的 run方法
    Runnable runnable =  new Runnable() {
        @Override
        public void run() {
            //执行打印,真实开发中,是这些我们的业务代码。
            System.out.println("防抖操作执行了:do task: "+System.currentTimeMillis());
        }
    };

    //runnable:要执行的任务,通过参数传递进去。1000L:1秒执行内没有请求,就执行一次防抖操作
    DebounceTask task = DebounceTask.build(runnable,1000L);
    //请求持续时间
    long delay = 100;
    //休眠时间,为了让防抖任务执行
    long douDelay = 0;

    //while 死循环,请求一直执行
    while (true){
        System.out.println("请求执行:call task: "+System.currentTimeMillis());
        //调用 DebounceTask 防抖类中的 timerRun() 方法, 执行防抖任务
        task.timerRun();
        douDelay = douDelay+100;
        try {
            //如果请求执行了两秒,我们让他先休息两秒,在接着请求
            if (douDelay == 2000){
                Thread.sleep(douDelay);
            }
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Salin selepas log masuk

节流(throttle)

package com.example.test01.zhangch;

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

/**
 * @Author zhangch
 * @Description 节流
 * @Date 2022/8/6 15:41
 * @Version 1.0
 */
public class ThrottleTask {
    /**
     * 节流实现关键类
     */
    private Timer timer;
    private Long delay;
    private Runnable runnable;
    private boolean needWait=false;

    /**
     * 有参构造函数
     * @param runnable 要启动的定时任务
     * @param delay 延迟时间
     */
    public ThrottleTask(Runnable runnable,  Long delay) {
        this.runnable = runnable;
        this.delay = delay;
        this.timer = new Timer();
    }

    /**
     * build 创建对象,相当于 ThrottleTask task = new ThrottleTask();
     * @param runnable 要执行的节流任务
     * @param delay 延迟时间
     * @return ThrottleTask 对象
     */
    public static ThrottleTask build(Runnable runnable, Long delay){
        return new ThrottleTask(runnable, delay);
    }

    public void taskRun(){
        //如果 needWait 为 false,结果取反,表达式为 true。执行 if 语句 
        if(!needWait){
            //设置为 true,这样下次就不会再执行
            needWait=true;
            //执行节流方法
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    //执行完成,设置为 false,让下次操作再进入 if 语句中
                    needWait=false;
                    //开启多线程执行 run() 方法
                    runnable.run();
                }
            }, delay);
        }
    }
}
Salin selepas log masuk

节流测试1

节流测试,每 2ms 请求一次,节流任务是每 1s 执行一次。真实效果应该是 1s 内前端发起了五次请求,但是后端只执行了一次操作

public static void main(String[] args){
    //创建节流要执行的对象,并把要执行的任务传入进去
    ThrottleTask task = ThrottleTask.build(new Runnable() {
        @Override
        public void run() {
            System.out.println("节流任务执行:do task: "+System.currentTimeMillis());
        }
    },1000L);
    //while一直执行,模拟前端用户一直请求后端
    while (true){
        System.out.println("前端请求后端:call task: "+System.currentTimeMillis());
        task.taskRun();
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
Salin selepas log masuk

结果如我们所料

前端请求后端:call task: 1659772459363
前端请求后端:call task: 1659772459574
前端请求后端:call task: 1659772459780
前端请求后端:call task: 1659772459995
前端请求后端:call task: 1659772460205
节流任务执行:do task: 1659772460377
前端请求后端:call task: 1659772460409
前端请求后端:call task: 1659772460610
前端请求后端:call task: 1659772460812
前端请求后端:call task: 1659772461027
前端请求后端:call task: 1659772461230
节流任务执行:do task: 1659772461417

彩蛋

idea 爆红线了,强迫症的我受不了,肯定要解决它

Bagaimana untuk melaksanakan anti goncang dan pendikit di Jawa

解决方法1

脑子第一时间冒出来的是 @SuppressWarnings("all") 注解,跟所有的警告说拜拜~瞬间就清爽了

Bagaimana untuk melaksanakan anti goncang dan pendikit di Jawa

解决方法2

算了,压制警告总感觉是不负责任。总不能这样草草了事,那就来直面这个爆红。既然让我用 ScheduledExecutorService ,那简单,直接替换

public class ThrottleTask {
    /**
     * 节流实现关键类:
     */
    private ScheduledExecutorService timer;
    private Long delay;
    private Runnable runnable;
    private boolean needWait=false;

    /**
     * 有参构造函数
     * @param runnable 要启动的定时任务
     * @param delay 延迟时间
     */
    public ThrottleTask(Runnable runnable,  Long delay) {
        this.runnable = runnable;
        this.delay = delay;
        this.timer = Executors.newSingleThreadScheduledExecutor();
    }

    /**
     * build 创建对象,相当于 ThrottleTask task = new ThrottleTask();
     * @param runnable 要执行的节流任务
     * @param delay 延迟时间
     * @return ThrottleTask 对象
     */
    public static ThrottleTask build(Runnable runnable, Long delay){
        return new ThrottleTask(runnable, delay);
    }

    public void taskRun(){
        //如果 needWait 为 false,结果取反,表达式为 true。执行 if 语句
        if(!needWait){
            //设置为 true,这样下次就不会再执行
            needWait=true;
            //执行节流方法
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    //执行完成,设置为 false,让下次操作再进入 if 语句中
                    needWait=false;
                    //开启多线程执行 run() 方法
                    runnable.run();
                }
            }, delay,TimeUnit.MILLISECONDS);
        }
    }
}
Salin selepas log masuk

那么定时器 Timer 和 ScheduledThreadPoolExecutor 解决方案之间的主要区别是什么,我总结了三点...

  • 定时器对系统时钟的变化敏感;ScheduledThreadPoolExecutor并不会。

  • 定时器只有一个执行线程;ScheduledThreadPoolExecutor可以配置任意数量的线程。

  • TimerTask中抛出的运行时异常会杀死线程,因此后续的计划任务不会继续运行;使用ScheduledThreadExecutor–当前任务将被取消,但其余任务将继续运行。

Atas ialah kandungan terperinci Bagaimana untuk melaksanakan anti goncang dan pendikit di Jawa. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:yisu.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan