外贸网站推广方案,长春网站建设流程,263企业邮箱入口注册,Wordpress 当天文章更新数定时器
定时器时我们日常开发中会用到的组件工具#xff0c;类似于一个闹钟#xff0c;设定一个时间#xff0c;等到了时间#xff0c;定时器最自动的去执行某个逻辑#xff0c;比如博客的定时发布#xff0c;就是使用到了定时器 Java标准库里面也提供了定时…定时器
定时器时我们日常开发中会用到的组件工具类似于一个闹钟设定一个时间等到了时间定时器最自动的去执行某个逻辑比如博客的定时发布就是使用到了定时器 Java标准库里面也提供了定时器的实现 定义一个timer添加多个任务每个任务都带有一个时间 定义任务的时候可以使用lambde表达式吗 答案是不能的lambde只能用于创建函数式接口的实例如果非要用lambde表达式创建一个类的实例的话可以用lambde先创建出一个函数式接口的实例再把这个函数式接口赋值给类的变量如下图我们的源代码里面Timer就是一个实现了Runnable函数式接口的一个抽象类是不可以使用lambde表达式的 内置了前台线程 我们上图代码的执行结果如下 我们发现控制台打印了我们的三个任务以后并没有进程结束的提示说明我们的进程并没有结束原因是Timer里面内置了前台线程它会阻止进程的结束 但是我们往timer里面添加的任务都执行完了也不会结束吗 因为我们的timer也不知道你是否还会添加新任务进来所以它不能结束必须严阵以待也就是不能结束于是内置了前台线程 但是就没有办法让timer结束吗 timer里面有一个cancel方法可以手动调用来结束进程 上述代码我们调用了cancel后进程会结束(如下图) 需要主动调用cancel让线程主动结束要不然Timer不知道是否还有其他地方要添加任务的 定时器的实现 我们先思考一下实现一个定时器需要哪些的内容 首先我们需要一个线程帮助我们掐算时间时间一到的话这个线程就会执行该任务其次我们需要一个容器能够保存schedule进来的任务 我们直观的来想的话我们这个线程就要不断的遍历我们这个容器看看任务的时间是否到了如果到了就执行这个任务 但是如果我们容器里面的元素很多呢要是遍历的话时间复杂度就是o(n)了开销就很大了 我们此时就需要用到优先级队列了我们的每个任务都有实现先执行时间小的后执行时间大的有了优先级队列必须是小根堆队首元素就是执行时间最小的元素我们每次只需要看一下队首元素是否到时间了要是队首元素也没有到时间的话其他的任务一定没有到时间 我们现在的优先级队列有两个选择 PriorityQueue(线程不安全)PriorityBloskingQueue(线程安全) 虽然PriorityBloskingQueue是线程安全的但是我们这里要使用 PriorityQueue使用PriorityBloskingQueue不太好控制容易出问题我们这里手动给PriorityQueue加锁即可 上面是我们写的一个类用来描述一个任务 我们这个类直接实现Runnable也是可以的我们这里是让这个类持有了Runnable 而且我们这个任务类是需要将其放到优先级队列里面的所以要求我们这个类是可以比较的我们这里也实现了Comparable接口并且重写了CompareTo方法这里的比较的规则就是时间的大小 如果是TreeSet和TreeMap的话我们要求元素是可以比较的我们就需要实现Comparable和Comparator接口 如果是HsahSet和HashMap的话就要求元素是可以比较相等的和可哈希的这时候就要equals和hashCode方法了有时候为了让hsah更加高效的话需要重写这两个方法 这是我们写的构造方法在这里面我们创建了一个线程这个线程就是我们的判断和执行任务的线程 加锁 由于我们的加入任务的操作(如下图)和我们的执行并且删除任务的操作都是对同一个队列进行操作可能会有线程安全问题 可以发现我们都给这两个方法加上锁了 当我们线程如果发现队列里面是空的locker.wait就会释放锁于是scedule就可以获取到锁了获取到锁之后就可以往队列里面添加任务添加完任务之后notify就可以将线程唤醒 我们红框部分的地方也要用到wait是有时间限制的wait这里有两种情况 我们能进入else就说明还没有到首队列元素的执行时间此时我们需要等待(任务执行时间-当前时间)这么多的时间等到了我们wait的时间wait就会自动唤醒再次进入循环取出队首元素发现到时间了于是就执行任务并且将任务从队列里面删除我们进入else执行wait释放锁并且阻塞的时候此时又有一个任务通过schedule进入到了队列schedule里面的notify就会将我们的线程唤醒线程唤醒之后又进入循环由于我们加入了新的任务这个新任务的时间有可能比我们原来的队首任务的时间小也有可能大这时我们的队首任务就会发生变化于是又peek一下取队首元素看看是否到了时间在根据条件执行下面的逻辑 如果我们else里面什么都不加的话只有一个coontinue这时我的CPU只是在忙等虽然在等但是CPU很忙因为此时线程的情况是进入了死循环不如将CPU的资源让出来给其他的线程使用这就是我们wait的另一个作用 使用sleep可以吗 不可以sleep虽然也可以实现等待的结果但是sleep没有释放锁如果我们中间有一个schedule又加入了一个任务这个任务的执行时间是102000比如现在是100000我们的首队列元素的执行时间是103000此时我们进入else执行到了sleep按照我们上面wait的代码我们这里要sleep30分钟这个过程中锁没有被释放是被判断的线程持有的这就导致我们的schedule方法获取不到锁无法将新的任务添加到队列等sleep到了时间被唤醒的时候已经过了102000了这个任务就错过了 执行过程详解 执行到这里以后我们会进入到漫长的3s的等待3s结束之后wait就自动唤醒了