国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java多線程案例之定時(shí)器

這篇具有很好參考價(jià)值的文章主要介紹了Java多線程案例之定時(shí)器。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一. 定時(shí)器概述

1. 什么是定時(shí)器

定時(shí)器是一種實(shí)際開(kāi)發(fā)中非常常用的組件, 類似于一個(gè) “鬧鐘”, 達(dá)到一個(gè)設(shè)定的時(shí)間之后, 就執(zhí)行某個(gè)指定好的代碼.

  • 比如網(wǎng)絡(luò)通信中, 如果對(duì)方 500ms 內(nèi)沒(méi)有返回?cái)?shù)據(jù), 則斷開(kāi)連接嘗試重連.
  • 比如一個(gè) Map, 希望里面的某個(gè) key 在 3s 之后過(guò)期(自動(dòng)刪除).

類似于這樣的場(chǎng)景就需要用到定時(shí)器.

2. 標(biāo)準(zhǔn)庫(kù)中的定時(shí)器

標(biāo)準(zhǔn)庫(kù)中提供了一個(gè) Timer 類, Timer 類的核心方法為schedule.

Timer類構(gòu)造時(shí)內(nèi)部會(huì)創(chuàng)建線程, 有下面的四個(gè)構(gòu)造方法, 可以指定線程名和是否將定時(shí)器內(nèi)部的線程指定為后臺(tái)線程(即守護(hù)線程), 如果不指定, 定時(shí)器對(duì)象內(nèi)部的線程默認(rèn)為前臺(tái)線程.

序號(hào) 構(gòu)造方法 解釋
1 public Timer() 無(wú)參, 定時(shí)器關(guān)聯(lián)的線程為前臺(tái)線程, 線程名為默認(rèn)值.
2 public Timer(boolean isDaemon) 指定定時(shí)器中關(guān)聯(lián)的線程類型, true(后臺(tái)線程), false(前臺(tái)線程).
3 public Timer(String name) 指定定時(shí)器關(guān)聯(lián)的線程名, 線程類型為前臺(tái)線程
4 public Timer(String name, boolean isDaemon) 指定定時(shí)器關(guān)聯(lián)的線程名和線程類型

schedule 方法是給Timer注冊(cè)一個(gè)任務(wù), 這個(gè)任務(wù)在指定時(shí)間后進(jìn)行執(zhí)行, TimerTask類就是專門(mén)描述定時(shí)器任務(wù)的一個(gè)抽象類, 它實(shí)現(xiàn)了Runnable接口.

public abstract class TimerTask implements Runnable // jdk源碼
序號(hào) 方法 解釋
1 public void schedule(TimerTask task, long delay) 指定任務(wù), 延遲多久執(zhí)行該任務(wù)
2 public void schedule(TimerTask task, Date time) 指定任務(wù), 指定任務(wù)的執(zhí)行時(shí)間
3 public void schedule(TimerTask task, long delay, long period) 連續(xù)執(zhí)行指定任務(wù), 延遲時(shí)間, 連續(xù)執(zhí)行任務(wù)的時(shí)間間隔, 毫秒為單位
4 public void schedule(TimerTask task, Date firstTime, long period) 連續(xù)執(zhí)行指定任務(wù), 第一次任務(wù)的執(zhí)行時(shí)間, 連續(xù)執(zhí)行任務(wù)的時(shí)間間隔
5 public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 與方法4作用相同
6 public void scheduleAtFixedRate(TimerTask task, long delay, long period) 與方法3作用相同
7 public void cancel() 清空任務(wù)隊(duì)列中的全部任務(wù), 正在執(zhí)行的任務(wù)不受影響.

代碼示例:

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

public class TestProgram {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("執(zhí)行延后3s的任務(wù)!");
            }
        }, 3000);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("執(zhí)行延后2s后的任務(wù)!");
            }
        }, 2000);
        
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("執(zhí)行延后1s的任務(wù)!");
            }
        }, 1000);
    }
}

執(zhí)行結(jié)果:

java實(shí)現(xiàn)兩個(gè)定時(shí)線程,JavaWeb,java,定時(shí)器,Timer,多線程,線程安全

觀察執(zhí)行結(jié)果, 任務(wù)執(zhí)行結(jié)束后程序并沒(méi)有結(jié)束, 即進(jìn)程并沒(méi)有結(jié)束, 這是因?yàn)樯厦娴拇a定時(shí)器內(nèi)部是開(kāi)啟了一個(gè)線程去執(zhí)行任務(wù)的, 雖然任務(wù)執(zhí)行完成了, 但是該線程并沒(méi)有銷毀; 這和自己定義一個(gè)線程執(zhí)行完成 run 方法后就自動(dòng)銷毀是不一樣的, Timer 本質(zhì)上是相當(dāng)于線程池, 它緩存了一個(gè)工作線程, 一旦任務(wù)執(zhí)行完成, 該工作線程就處于空閑狀態(tài), 等待下一輪任務(wù).

二. 定時(shí)器的簡(jiǎn)單實(shí)現(xiàn)

首先, 我們需要定義一個(gè)類, 用來(lái)描述一個(gè)定時(shí)器當(dāng)中的任務(wù), 類要成員要有一個(gè)Runnable, 再加上一個(gè)任務(wù)執(zhí)行的時(shí)間戳, 具體還包含如下內(nèi)容:

  • 構(gòu)造方法, 用來(lái)指定任務(wù)和任務(wù)的延遲執(zhí)行時(shí)間.
  • 兩個(gè)get方法, 分別用來(lái)給外部對(duì)象獲取該對(duì)象的任務(wù)和執(zhí)行時(shí)間.
  • 實(shí)現(xiàn)Comparable接口, 指定比較方式, 用于判斷定時(shí)器任務(wù)的執(zhí)行順序, 每次需要執(zhí)行時(shí)間最早的任務(wù).
class MyTask implements Comparable<MyTask>{
    //要執(zhí)行的任務(wù)
    private Runnable runnable;
    //任務(wù)的執(zhí)行時(shí)間
    private long time;

    public MyTask(Runnable runnable, long time) {
        this.runnable = runnable;
        this.time = time;
    }

    //獲取當(dāng)前任務(wù)的執(zhí)行時(shí)間
    public long getTime() {
        return this.time;
    }
    //執(zhí)行任務(wù)
    public void run() {
        runnable.run();
    }

    @Override
    public int compareTo(MyTask o) {
        return (int) (this.time - o.time);
    }
}

然后就需要實(shí)現(xiàn)定時(shí)器類了, 我們需要使用一個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)組織定時(shí)器中的任務(wù), 需要每次都能將時(shí)間最早的任務(wù)找到并執(zhí)行, 這個(gè)情況我們可以考慮用優(yōu)先級(jí)隊(duì)列(即小根堆)來(lái)實(shí)現(xiàn), 當(dāng)然我們還需要考慮線程安全的問(wèn)題, 所以我們選用優(yōu)先級(jí)阻塞隊(duì)列 PriorityBlockingQueue 是最合適的, 特別要注意在自定義的任務(wù)類當(dāng)中要實(shí)現(xiàn)比較方式, 或者實(shí)現(xiàn)一下比較器也行.

private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();

我們自己實(shí)現(xiàn)的定時(shí)器類中要有一個(gè)注冊(cè)任務(wù)的方法, 用來(lái)將任務(wù)插入到優(yōu)先級(jí)阻塞隊(duì)列中;

還需要有一個(gè)線程用來(lái)執(zhí)行任務(wù), 這個(gè)線程是從優(yōu)先級(jí)阻塞隊(duì)列中取出隊(duì)首任務(wù)去執(zhí)行, 如果這個(gè)任務(wù)還沒(méi)有到執(zhí)行時(shí)間, 那么線程就需要把這個(gè)任務(wù)再放會(huì)隊(duì)列當(dāng)中, 然后線程就進(jìn)入等待狀態(tài), 線程等待可以使用sleepwait, 但這里有一個(gè)情況需要考慮, 當(dāng)有新任務(wù)插入到隊(duì)列中時(shí), 我們需要喚醒線程重新去優(yōu)先級(jí)阻塞隊(duì)列拿隊(duì)首任務(wù), 畢竟新注冊(cè)的任務(wù)的執(zhí)行時(shí)間可能是要比前一陣拿到的隊(duì)首任務(wù)時(shí)間是要早的, 所以這里使用wait進(jìn)行進(jìn)行阻塞更合適, 那么喚醒操作就需要使用notify來(lái)實(shí)現(xiàn)了.

實(shí)現(xiàn)代碼如下:

//自己實(shí)現(xiàn)的定時(shí)器類
class MyTimer {
    //掃描線程
    private Thread t = null;
    //阻塞隊(duì)列,存放任務(wù)
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();

    public MyTimer() {
        //構(gòu)造掃描線程
        t = new Thread(() -> {
           while (true) {
               //取出隊(duì)首元素,檢查隊(duì)首元素執(zhí)行任務(wù)的時(shí)間
               //時(shí)間沒(méi)到,再把任務(wù)放回去
               //時(shí)間到了,就執(zhí)行任務(wù)
               try {
                   synchronized (this) {
                       MyTask task = queue.take();
                       long curTime = System.currentTimeMillis();
                       if (curTime < task.getTime()) {
                           //時(shí)間沒(méi)到,放回去
                           queue.put(task);
                           //放回任務(wù)后,不應(yīng)該立即就再次取出該任務(wù)
                           //所以wait設(shè)置一個(gè)阻塞等待,以便新任務(wù)到時(shí)間或者新任務(wù)來(lái)時(shí)后再取出來(lái)
                           this.wait(task.getTime() - curTime);
                       } else {
                           //時(shí)間到了,執(zhí)行任務(wù)
                           task.run();
                       }
                   }
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);

               }
           }
        });
        t.start();
    }

    /**
     * 注冊(cè)任務(wù)的方法
     * @param runnable 任務(wù)內(nèi)容
     * @param after 表示在多少毫秒之后執(zhí)行. 形如 1000
     */
    public void schedule (Runnable runnable, long after) {
        //獲取當(dāng)前時(shí)間的時(shí)間戳再加上任務(wù)時(shí)間
        MyTask task = new MyTask(runnable, System.currentTimeMillis() + after);
        queue.put(task);
        //每次當(dāng)新任務(wù)加載到阻塞隊(duì)列時(shí),需要中途喚醒線程,因?yàn)樾逻M(jìn)來(lái)的任務(wù)可能是最早需要執(zhí)行的
        synchronized (this) {
            this.notify();
        }
    }
}

要注意上面掃描線程中的synchronized并不能只要針對(duì)wait方法加鎖, 如果只針對(duì)wait加鎖的話, 考慮一個(gè)極端的情況, 假設(shè)的掃描線程剛執(zhí)行完put方法, 這個(gè)線程就被cpu調(diào)度走了, 此時(shí)另有一個(gè)線程在隊(duì)列中插入了新任務(wù), 然后notify喚醒了線程, 而剛剛并沒(méi)有執(zhí)行wait阻塞, notify就沒(méi)有起到什么作用, 當(dāng)cpu再調(diào)度到這個(gè)線程, 這樣的話如果新插入的任務(wù)要比原來(lái)隊(duì)首的任務(wù)時(shí)間更早, 那么這個(gè)新任務(wù)就被錯(cuò)過(guò)了執(zhí)行時(shí)間, 這些線程安全問(wèn)題真是防不勝防啊, 所以我們需要保證這些操作的原子性, 也就是上面的代碼, 擴(kuò)大鎖的范圍, 保證每次notify都是有效的.

那么最后基于上面的代碼, 我們來(lái)測(cè)試一下這個(gè)定時(shí)器:

public class TestDemo23 {
    public static void main(String[] args) {
        MyTimer timer = new MyTimer();
        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("2s后執(zhí)行的任務(wù)1");
            }
        }, 2000);

        timer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("2s后執(zhí)行的任務(wù)1");
            }
        }, 1000);
    }
}

執(zhí)行結(jié)果:

java實(shí)現(xiàn)兩個(gè)定時(shí)線程,JavaWeb,java,定時(shí)器,Timer,多線程,線程安全文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-829902.html

到了這里,關(guān)于Java多線程案例之定時(shí)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Java|多線程與高并發(fā)】定時(shí)器(Timer)詳解

    【Java|多線程與高并發(fā)】定時(shí)器(Timer)詳解

    在Java中,定時(shí)器 Timer 類是用于執(zhí)行定時(shí)任務(wù)的工具類。它允許你安排一個(gè)任務(wù)在未來(lái)的某個(gè)時(shí)間點(diǎn)執(zhí)行,或者以固定的時(shí)間間隔重復(fù)執(zhí)行。 在服務(wù)器開(kāi)發(fā)中,客戶端向服務(wù)器發(fā)送請(qǐng)求,然后等待服務(wù)器響應(yīng). 但服務(wù)器什么時(shí)候返回響應(yīng),并不確定. 但也不能讓客戶端一直等下去

    2024年02月07日
    瀏覽(20)
  • 多線程案例(3)-定時(shí)器

    大家好,我是曉星航。今天為大家?guī)?lái)的是 多線程案例三 相關(guān)的講解!?? 定時(shí)器是什么 定時(shí)器也是軟件開(kāi)發(fā)中的一個(gè)重要組件. 類似于一個(gè) “鬧鐘”. 達(dá)到一個(gè)設(shè)定的時(shí)間之后, 就執(zhí)行某個(gè)指定 好的代碼. 定時(shí)器是一種實(shí)際開(kāi)發(fā)中非常常用的組件. 比如網(wǎng)絡(luò)通信中, 如果對(duì)方

    2024年02月14日
    瀏覽(17)
  • 多線程案例 | 單例模式、阻塞隊(duì)列、定時(shí)器、線程池

    多線程案例 | 單例模式、阻塞隊(duì)列、定時(shí)器、線程池

    單例模式 單例模式是 設(shè)計(jì)模式 的一種 什么是設(shè)計(jì)模式? 設(shè)計(jì)模式好比象棋中的 “棋譜”,紅方當(dāng)頭炮,黑方馬來(lái)跳,針對(duì)紅方的一些走法,黑方應(yīng)招的時(shí)候有一些固定的套路,按照套路來(lái)走局勢(shì)就不會(huì)吃虧,也就發(fā)明了一組\\\"棋譜\\\",稱為設(shè)計(jì)模式 軟件開(kāi)發(fā)中也有很多常見(jiàn)

    2024年02月15日
    瀏覽(26)
  • JavaEE & 線程案例 & 定時(shí)器 & 線程池 and 工廠模式

    JavaEE & 線程案例 & 定時(shí)器 & 線程池 and 工廠模式

    歡迎光臨 ^ V ^ 定時(shí)器,可以理解為鬧鐘 我們?cè)O(shè)立一個(gè)時(shí)間,時(shí)間一到,讓一個(gè)線程跑起來(lái)~ 而Java標(biāo)準(zhǔn)庫(kù)提供了一個(gè)定時(shí)器類: Timer ,from java.util 1.1 定時(shí)器Timer的使用 1.1.1 核心方法schedule 傳入任務(wù)引用(TimerTask task)和 “定時(shí)”(long delay / ms) 由于TimerTask不是函數(shù)式接口,

    2023年04月18日
    瀏覽(18)
  • C++ 實(shí)現(xiàn)定時(shí)器的兩種方法(線程定時(shí)和時(shí)間輪算法修改版)

    定時(shí)器要求在固定的時(shí)間異步執(zhí)行一個(gè)操作,比如boost庫(kù)中的boost::asio::deadline_timer,以及MFC中的定時(shí)器。也可以利用c++11的thread, mutex, condition_variable 來(lái)實(shí)現(xiàn)一個(gè)定時(shí)器。 1、使用C++11中的thread, mutex, condition_variable來(lái)實(shí)現(xiàn)一個(gè)定時(shí)器。 注:此算法會(huì)每一個(gè)任務(wù)創(chuàng)建一個(gè)線程,不推

    2024年02月05日
    瀏覽(28)
  • Java定時(shí)器

    Java定時(shí)器

    目錄 什么是定時(shí)器? 如何使用定時(shí)器? schedule Timer的構(gòu)造方法 cancel 定時(shí)器的模擬實(shí)現(xiàn) 思路分析 實(shí)現(xiàn)過(guò)程 完整代碼 定時(shí)器: 即在設(shè)定的時(shí)間時(shí)執(zhí)行某事的設(shè)備(例如鬧鐘,在指定的時(shí)間響鈴),Java中的定時(shí)器會(huì)在到達(dá)設(shè)定的時(shí)間后,執(zhí)行指定的代碼 Java標(biāo)準(zhǔn)庫(kù)中提供了一

    2024年02月03日
    瀏覽(14)
  • Java定時(shí)器 @Scheduled注解的使用

    Java定時(shí)器 @Scheduled注解的使用

    @Scheduled注解可以用于做定時(shí)任務(wù),再方法上加上@Scheduled注解,可以將這個(gè)方法定義為一個(gè)任務(wù)發(fā)放,可以搭配cron表達(dá)式進(jìn)行任務(wù)的控制。 開(kāi)啟定時(shí)任務(wù)時(shí)在類上加注解 @EnableScheduling 1.按順序依次為 秒 分 時(shí) 天 月 周 年 表達(dá)式長(zhǎng)度為6個(gè)或者7個(gè) cron表達(dá)式是一個(gè)字符串,分為

    2024年02月04日
    瀏覽(16)
  • 【多線程】定時(shí)器,詳解定時(shí)器原理,讓大家更深刻的理解多線程

    【多線程】定時(shí)器,詳解定時(shí)器原理,讓大家更深刻的理解多線程

    前言: 大家好,我是 良辰丫 ,今天我們一起了解一下定時(shí)器,通過(guò)定時(shí)器來(lái)熟悉一下線程安全等相關(guān)知識(shí)點(diǎn).?????? ??個(gè)人主頁(yè):良辰針不戳 ??所屬專欄:javaEE初階 ??勵(lì)志語(yǔ)句:生活也許會(huì)讓我們遍體鱗傷,但最終這些傷口會(huì)成為我們一輩子的財(cái)富。 ??期待大家三連,關(guān)注

    2024年02月01日
    瀏覽(27)
  • 多線程---定時(shí)器

    定時(shí)器的功能和“鬧鐘”類似,代碼中的定時(shí)器通常都是“多長(zhǎng)時(shí)間之后,執(zhí)行某個(gè)動(dòng)作”。 注: 一個(gè)定時(shí)器可以安排多個(gè)任務(wù)。 調(diào)用schedule安排任務(wù)時(shí),一定要重寫(xiě)run方法,明確任務(wù)內(nèi)容 定時(shí)器開(kāi)啟后不會(huì)自動(dòng)結(jié)束,得手動(dòng)殺死進(jìn)程 版本一:實(shí)現(xiàn)簡(jiǎn)單的定時(shí)器 schedule方法

    2024年02月08日
    瀏覽(24)
  • JAVAEE-定時(shí)器案例

    JAVAEE-定時(shí)器案例

    設(shè)置一個(gè)時(shí)間,當(dāng)時(shí)間到了的時(shí)候,定時(shí)器就會(huì)去自動(dòng)執(zhí)行某個(gè)邏輯. 這里timer里面的任務(wù)執(zhí)行完了也并不會(huì)結(jié)束,因?yàn)樗⒉恢朗欠襁€會(huì)添加新的任務(wù)進(jìn)去, 處在嚴(yán)陣以待的狀態(tài) 此時(shí)如果我們想要結(jié)束,應(yīng)該使用cancel主動(dòng)去結(jié)束. 1)需要有一個(gè)線程,負(fù)責(zé)掐時(shí)間,等任務(wù)到達(dá)合適的

    2024年02月05日
    瀏覽(26)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包