工具-----滴答滴答(Java计时器)

2023-11-09 03:50
文章标签 java 工具 计时器 滴答

本文主要是介绍工具-----滴答滴答(Java计时器),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Java计时器

一、作用:

计时器也就是用来计时的东西。当你需要隔一段时间去干一件事的时候就可以用到它,比如:

  1. 当某拼夕夕网站的抢购在一段规定的时间内需要结束时。
  2. 比如某宝的页面需要在一段规定的时间里刷新页面时。
  3. 当你设置的闹钟在规定时间将你叫醒。

而此时我们要做的事可以写成一个接口,由用户规定干什么事情。

二、实现原理:

  1. wait(); 调用此方法将使该线程进入阻塞态,直到被notify才会重新进入就绪态。
  2. wait(int gap); 调用此方法将使该线程进入阻塞态,直到被notify才会重新进入就绪态。设置了超时时间的wait方法一旦过了时间,并不需要其他线程执行notify也能自动解除阻塞。
  3. lock.notify();调用此方法将lock锁上的线程唤醒;

对于sleep:sleep()方法在睡眠的时候一直占用锁资源,也就是说,sleep睡眠时间没有到,其它线程就得不到锁,无法进入就绪态,得不到CPU的使用权。因此使用sleep()方法会浪费CPU的资源,所以后面使用wait()方法。

三、方案阐述即代码展示:

  • 方案:
  1. 首先定义一个接口,此接口中的方法时使用者自己写的要定时执行的任务。
  2. 其次新建一个类有两个线程,一个线程用来计时,一个线程用来执行任务。

(对于为什么给两个线程?答:因为若只有一个线程即计时也执行任务,但要考虑到任务的执行也是需要占用时间的,会造成计时误差。所以开辟出两个线程去执行)

  • 代码显示:
package com.smy.timer.didadida;public interface IDidadida {private static final int DEFAULT_dELAY_tIME = 1000;void doSomething();
}
package com.smy.timer.didadida;import java.util.concurrent.ScheduledThreadPoolExecutor;public class Didadida implements Runnable { //延迟时间   private int delayTime;//对象锁private Object lock;//开始计时和结束计时的标志private volatile boolean goon;//接口(接口中的方法即任务)private IDidadida didadida;public Didadida() {this(DEFAULT_dELAY_tIME, null);}//初始化public Didadida(int delayTime, IDidadida didadida) {lock = new Object();this.delayTime = delayTime;this.didadida = didadida;}//可以由用户来设置public void setDidadida(IDidadida didadida) {this.didadida = didadida;}//开始计时public void startTimer() {this.goon = true;//开启两个线程new Thread(new TimeWorker(), "timeWorker").start();new Thread(this, "didadida").start();}//结束计时public void endTimer() {if (goon == false) {System.out.println("now had ended");return;}if (didadida == null) {System.out.println("无事可做!");return;}this.goon = false;}//用来计时的线程@Overridepublic void run() {while (goon) {synchronized (lock) {try {lock.wait(delayTime);//这里是唤醒一个线程,用来专门执行任务lock.notify();} catch (InterruptedException e) {e.printStackTrace();}}}}//内部类(用来执行任务)class TimeWorker implements Runnable {@Overridepublic void run() {while (goon) {synchronized (lock) {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}didadida.doSomething();}}}
}

当然我们要看的核心当然是两个线程的执行:就是关于锁

首先,两个线程我们当然要让计时线程先跑起来,但由于时间片和优先级等的不确定性,我们必须用锁来加以限制。

  1. 给执行线程和计时线程都加锁,但在执行线程的一开始wait();这样就算执行线程得到CPU也可以先阻塞它。
  2. 而计时线程必将进入自己的锁块,并wait(delayTime);后再去唤醒执行线程执行dosomething方法。

注:此代码有两个需要注意的地方

  1. 若执行任务线程中执行dosomething的时间过长,还没有进入阻塞态,而计时线程已经去notify了,这时会无线程可唤醒。只能等下次线程去唤醒,所以当wait时间和dosomething的执行时间差距过大,将会产生成倍时间的误差,比如wait一秒,但是执行dosomething需要两秒,这时在第1秒去notify时还没执行完在第2秒notify时才会再去执行,这时我们设置的时间虽然是一秒,但其实是两秒(0秒时执行,2秒时执行......)。所以此时我们的工具是有误差的。
  2. dosomething方法必须写在锁块的外面,若在锁块里面,就必须等待执行完dosomething才能释放锁,这样就会产生计时误差。

 四、Test测试:

package com.smy.timer.didadida.test;import java.text.SimpleDateFormat;import com.smy.timer.didadida.Didadida;
import com.smy.timer.didadida.IDidadida;public class Test {public static void main(String[] args) {Didadida didadida = new Didadida(1000, new IDidadida() {SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");@Overridepublic void doSomething() {String data = sdf.format(System.currentTimeMillis());System.out.println("-------" + data);}});System.out.println("开始");didadida.startTimer();//		didadida.endTimer();}}

结果:给的参数是一秒

下面给出其缺陷的Test:

package com.smy.timer.didadida.test;import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;import com.smy.timer.didadida.Didadida;
import com.smy.timer.didadida.IDidadida;public class Test {public static void main(String[] args) {Didadida didadida = new Didadida(1000, new IDidadida() {File file = new File("E:\\test.txt");SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");@Overridepublic void doSomething() {FileOutputStream fileOutputStream = null;try {fileOutputStream = new FileOutputStream(file);} catch (FileNotFoundException e1) {e1.printStackTrace();}for (int i = 0; i < 1000000; i++) {try {fileOutputStream.write(i);} catch (IOException e) {e.printStackTrace();}}String data = sdf.format(System.currentTimeMillis());System.out.println("-------" + data);try {fileOutputStream.close();} catch (IOException e) {e.printStackTrace();}}});System.out.println("开始");didadida.startTimer();//		didadida.endTimer();}}

 

可以看出是五秒一次即1的整数倍。 

这篇关于工具-----滴答滴答(Java计时器)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/373866

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

高效录音转文字:2024年四大工具精选!

在快节奏的工作生活中,能够快速将录音转换成文字是一项非常实用的能力。特别是在需要记录会议纪要、讲座内容或者是采访素材的时候,一款优秀的在线录音转文字工具能派上大用场。以下推荐几个好用的录音转文字工具! 365在线转文字 直达链接:https://www.pdf365.cn/ 365在线转文字是一款提供在线录音转文字服务的工具,它以其高效、便捷的特点受到用户的青睐。用户无需下载安装任何软件,只