当前位置: 首页 > wzjs >正文

做网站公司运营部百度竞价排名点击软件

做网站公司运营部,百度竞价排名点击软件,简单的明星个人网站建设论文,大学生期末作业建设网站目录 ​编辑 定时器 定时器的使用 三.定时器的实现 MyTimer 3.1 分析思路 1. 创建执行任务的类。 2. 管理任务 3. 执行任务 3.2 线程安全问题 定时器 定时器是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某个指定好的…

目录

​编辑

定时器

定时器的使用 

三.定时器的实现 MyTimer

3.1 分析思路

1. 创建执行任务的类。

 2. 管理任务   

3. 执行任务

3.2 线程安全问题


 

定时器

定时器是软件开发中的一个重要组件. 类似于一个 "闹钟". 达到一个设定的时间之后, 就执行某个指定好的代码.

定时器的使用 

标准库中的定时器 标准库中提供了一个 Timer 类. Timer 类的核心方法为 schedule . schedule 包含两个参数.

第一个参数是继承timetask抽象类的类实例且内部重写了run方法(这里的匿名类隐式继承了TimerTask):指定即将要执行的任务代码(timetask实现了runable接口所以有run方法)

 第二个参数指定多长时间之后执行 (单位为毫秒).

Timer timer = new Timer();
timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello");}
}, 3000);

执行schedule方法的时候,系统把要执行的任务放到timer对象中,与此同时timer对象里头自带一个线程叫做“扫描线程”,一旦时间到扫描线程就会执行刚才安排的任务,执行完所有任务后线程也不会销毁,会阻塞等待直到其他的任务被放到timer对象中再继续执行(就这么重复

三.定时器的实现 MyTimer

3.1 分析思路

对于定时器来说:

  1. 创建描述一个要执行的任务(任务内容 + 执行任务时间)的类
  2. 管理多个任务,通过一定的数据结构,把多个任务存起来
  3. 有专门的线程,执行这里的任务
1. 创建执行任务的类。

   我们在调用 schedule 时,传的是延迟时间 “delay” 值。但是,描述任务时,不太建议使用 delay

表示,最好使用 “绝对时间”(时间戳)来表示~~

public class MyTimerTask implements Comparable<MyTimerTask>{//此处这里的 time,通过毫秒时间戳,表示这个任务具体啥时候执行private long time;private Runnable runnable;public  MyTimerTask(Runnable runnable,long delay){this.time = System.currentTimeMillis() + delay;this.runnable = runnable;}public void run(){runnable.run();}public long getTime(){return time;}@Overridepublic int compareTo(MyTimerTask o) {//比如,当前时间是 10:30,任务时间是 12:00,不应该执行//如果当前时间是 10:30,任务时间是 10:29,应该执行//谁减去谁,可以通过实验判断return (int) (this.time - o.time);}
}
 2. 管理任务   

使用 List 管理任务,不是一个好选择——因为后续执行列表中的任务时,就需要依次遍历每个元素;执行完毕后,还需要把对应的任务从 List 中删除掉。   
我们需要按照时间来执行这里的任务。只要能够确定所有任务中,时间最早的任务,判定它是否到该执行的时间即可。如果时间最早的任务还没到执行时间,其他任务更不可能到时间了。因此,我们使用堆数据结构(涉及到队列中的元素排序时,考虑堆)——PriorityQueue<MyTimerTask>(优先级队列管理元素时,需要有比较方法,才能排序存储。因此,在实现 MyTimerTask 类时,要继承 Comparable<MyTimerTask> 接口,重写 compareTo比较方法)

3. 执行任务

当创建 MyTimer 对象,调用无参构造方法时,便创建一个线程,循环执行从队列中取出任务的操作:取出队列中 “绝对时间” 最早的任务——如果当前时间 >= 此任务的时间(已经到达此任务的执行时间),便可调用run方法执行,执行完毕后从队列中删除; 如果当前时间 < 此任务的时间(没到此任务的执行时间),则继续执行循环。(所以,在实现 MyTimerTask 类时,要有 run方法 和 getTime方法)

   除此之外 ,还需要有 schedule 方法添加任务。

import java.util.PriorityQueue;public class MyTimer {private final PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();public MyTimer() {Thread t = new Thread(() -> {while (true){if(queue.isEmpty()){ continue;}MyTimerTask task = queue.peek();//判断是否满足执行条件if (System.currentTimeMillis() >= task.getTime()) {task.run();//执行完后,便从队列中删除queue.poll();}else{continue;}}});t.start();}public void schedule(Runnable runnable, long delay) {MyTimerTask task = new MyTimerTask(runnable, delay);queue.offer(task);}
}
3.2 线程安全问题

   当前这个代码,是没有考虑线程安全问题的。

   PriorityQueue 这个类自身,是非线程安全的,并且又是多个线程来进行操作,一定存在线程安全问题的风险。因此,要在涉及队列相关操作的地方加锁。(让删的时候不能进行加入操作,加的时候不进行删除操作)

import java.util.PriorityQueue;public class MyTimer {private final PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();private final Object locker = new Object();public MyTimer() {Thread t = new Thread(() -> {while (true){synchronized(locker){if(queue.isEmpty()){ continue;}MyTimerTask task = queue.peek();if (System.currentTimeMillis() >= task.getTime()) {task.run();queue.poll();}else{continue;}}}});t.start();}public void schedule(Runnable runnable, long delay) {synchronized(locker){MyTimerTask task = new MyTimerTask(runnable, delay);queue.offer(task);}}
}

 但是,加完锁以后,又出现了线程安全问题。 

1)初始情况下,如果队列中,没有任何元素。此时,就会在短时间内执行大量循环,这样的执行是没有意义的,导致“线程饿死”。

因此,我们需要添加 wait 和 notify 机制:队列为空时,进行等待;添加任务时,就唤醒线程。

2)假设队列中,已经包含元素了,并且当前时间是 10:45,任务时间 12:00(类似于,我定了12:00的闹钟,现在是 10:45)。在判断任务是否满足执行条件时,不满足就会一直循环(相当于每隔一会儿就看一眼闹钟),这样无意义的执行就一直占用着cpu资源,导致 “线程饿死”。

因此,我们需要添加一个有等待期限的 wait(等待 1h15min 就会执行),当到达任务执行时间,wait 就结束了。如果在等待过程中,又再次调用 schedule 方法,也会唤醒这里的 wait,进行新一轮的判断。

 线程安全版:

import java.util.PriorityQueue;public class MyTimer {private final PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();private final Object locker = new Object();public MyTimer() {Thread t = new Thread(() -> {try {while (true) {synchronized (locker) {while (queue.isEmpty()) {//如果还没添加任务,会不断循环执行判断,出现线程饿死。//continue;//因此,使用wait等待,当添加任务后唤醒locker.wait();}MyTimerTask task = queue.peek();if (System.currentTimeMillis() >= task.getTime()) {task.run();queue.poll();} else {//如果还没到任务执行时间,依旧不断循环判断,出现线程饿死。//continue;//因此,使用有等待期限的 wait,计算执行的时间与当前时间的差值//当添加新的任务后,wait 被唤醒,再进行新的判断locker.wait(task.getTime() - System.currentTimeMillis());}}}} catch (InterruptedException e) {e.printStackTrace();}});t.start();}public void schedule(Runnable runnable, long delay) {synchronized (locker){MyTimerTask task = new MyTimerTask(runnable, delay);queue.offer(task);// 唤醒 waitlocker.notify();}}
}

* 能否将第二处的 wait 改为 sleep 呢? ——不能!!

 不应该使用sleep,可能存在以下情况:
     1)在 sleep 阻塞1h15min 的过程中,新来了一个时间更早的任务,比如 11:30 要执行。如果使用 wait ,每次新来的任务,都会把 wait 唤醒,重新设定 wait 的等待时间。而 sleep 不会被唤醒,依旧在阻塞着.....
     2)sleep 休眠的时候,不会释放锁。因此,在休眠的时候就是“抱着锁”,其他人想拿锁就拿不到了。也就是说你休眠的时候,就不能进行增加线程

 * PriorityQueue 是线程不安全的类,能否使用 PriorityBlockingQueue 线程安全的阻塞队列呢?——不能!!    
如果使用线程安全的队列,会导致代码中从 一把锁 变成 两把锁,很容易出现死锁的情况,比如持有和请求的情况(并非100%一定出现,但是需要程序员精心控制加锁顺序,使得编写代码的复杂度提高了。如果通篇代码 只有一把锁,就能更容易地解决问题)

 

http://www.dtcms.com/wzjs/443224.html

相关文章:

  • 武汉做网站便宜公司哪家好自媒体推广平台
  • 视频分享网站建设网站怎么做推广和宣传
  • 网站加载慢在哪里查关键词排名
  • 易语言可以做网站管理系统吗招聘网络营销推广人员
  • 深圳网站制作公司报价单宁波seo教学
  • 小程序app开发软件定制西藏自治区seo 标题 关键词优化
  • 那里有帮做网站的班级优化大师官网下载
  • 建设外汇网站新网站多久会被百度收录
  • iis限制网站带宽优化关键词的作用
  • 8图片这样的网站怎么做关键词排名顾问
  • 唐山网站建设模板关键词智能优化排名
  • 推荐手机网站建设google全球推广
  • 长寿做网站的电话站长之家ip地址归属查询
  • 个人网站首页导航栏ps制作教程商业网站设计
  • 网页网站怎么做的徐州网站关键词排名
  • 罗湖附近公司做网站建设哪家效益快网络营销与网站推广的
  • 网站建设公司权威排名必应搜索网站
  • 手机免费做网站seo工程师是什么职业
  • seo诊断工具网站中国有几个搜索引擎
  • 彩票网站开发的网络外包
  • 廊坊做网站优化的公司厦门关键词优化平台
  • 网站建设佛山拓客科技seo网站优化服务
  • 重庆建设建设工程信息网站2023网站推广入口
  • 免费b站推广网站2021seo外链推广工具
  • 汉沽谁做网站seo内容优化
  • 网站建设咨询公百度推广后台登录入口
  • 专业做网站安全的sine安最新做做网站
  • 网站搜索排名和什么有关系sem是什么岗位
  • 做网站赔了8万解封后中国死了多少人
  • 诸暨网站开发windows优化大师怎么样