Timer的源码分析

         这段时间用到了Timer做一个定时任务,因为业务的原因就需要调计算机的时间,发现一个问题把时间先调大于当前时间在调回来发现timer就没有执行了,感觉Timer不会这么坑吧,所以就看了一下源码。下面就把我理解Timer的分享一下

       先看Timer类的结构里面内置二个重要的组件TimerThread(定时线程)和TaskQueue(任务队列)下面是Timer的部分源码


  我们现在分析类TimerThread


TimerThread是Thread的子类,里面内置TaskQueue对象,实现Runnable接口的run方法

在看看mainLoop方法



上面的方法告诉我们只要TaskQueue里面为空并且newTasksMayBeScheduled为true的话,这个线程一直处于等待状态。如果队列为空newTasksMayBeScheduled为false时候该线程就直接跑完了,其他情况的话先从任务队列里面取出下标为1的元素,计算一下当前时间和下个周期执行时间那个大,然后当前时间大于或等于下个一个周期执行时间

话,先计算个下下个执行周期时间然后跟新任务队列,并执行这个任务,否则直接等待(executionTime-currentTime)这个周期。然后在循环上面操作(读到这里当时我有个疑问是为什么下标为1的任务为什么是最近要执行的job,其实这个与TaskQueue这个类添加元素有关,下面会分析这个类)

      TaskQueue类里面有个TimerTask数组queue,核心方法有add(TimerTask task),getMin(),rescheduleMin(long newTime),fixUp(int k),fixDown(int k)下面我们一一分析



上图是fixDown和fixUp的源码。其实这里保证了当添加一个元素的时候和修改一个元素的下个执行周期的时候所有的子节点都大于或等于父节点


这个方法会在TimerThread中的mainLoop方法里被调用,当取出的任务的下一个执行时间大于等于当前时间的话会调用这个方法,因为在执行task的同时,需要修改计算这个任务的下个周期执行时间,并放到队列里面并要维护TaskQueue的特性(子节点的下个执行周期一定要大于父节点的执行周期)。这样保证getMin的时候取到的下个执行周期是最近的。


getMin的源码

现在介绍这二个主要的类,我们在看Timer类

我们




当我们添加一个TimerTask的时候会调用上面方法,加到TaskQueue队列中,与TimerThread的mainLoop不断重复处理



      在Timer的开发中在编码自己的TimerTask任务的时候注意要处理自己的异常,从上面的源码的可以知道他是一个主线程中循环处理queue里面的任务的,然后在执行的你的代码抛出异常的时候会导致整个定时任务崩溃不能正常工作

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Context包是Go语言内置的一个标准库,主要用于多个Goroutine之间的上下文传递和控制。它提供了一种机制来传递取消信号、截止时间和一些其他的请求/值,这些请求/值可以跨越多个API边界和Goroutine传递,而不需要显式地传递。 以下是Context包的主要源码分析: 1. Context接口 Context接口定义了一个可取消的上下文,它包括了Deadline截止时间、Done通道和Value键值对数据。 ```go type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{} } ``` 2. context.Background() Background函数返回一个空的Context,它没有任何值和截止时间,而且永远不会取消。它被广泛用于Main函数、初始化和测试中。 ```go func Background() Context { return background } var ( background = new(emptyCtx) ) type emptyCtx int func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { return } func (*emptyCtx) Done() <-chan struct{} { return nil } func (*emptyCtx) Err() error { return nil } func (*emptyCtx) Value(key interface{}) interface{} { return nil } ``` 3. context.TODO() TODO函数返回一个非空的Context,它没有任何值和截止时间,而且永远不会取消。它被广泛用于暂时不确定上下文应该是什么的情况。 ```go func TODO() Context { return todo } var ( todo = new(emptyCtx) ) ``` 4. context.WithCancel() WithCancel函数返回一个带有CancelFunc的Context,当CancelFunc调用时,Context的Done通道将被关闭。这个函数可以用来取消长时间运行的操作。 ```go func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := newCancelCtx(parent) propagateCancel(parent, &c) return &c, func() { c.cancel(true, Canceled) } } type cancelCtx struct { Context mu sync.Mutex // protects following fields done chan struct{} // created lazily, closed by first cancel call children map[canceler]struct{} // set to nil by the first cancel call err error // set to non-nil by the first cancel call } func newCancelCtx(parent Context) cancelCtx { return cancelCtx{Context: parent} } func (c *cancelCtx) Done() <-chan struct{} { c.mu.Lock() if c.done == nil { c.done = make(chan struct{}) } d := c.done c.mu.Unlock() return d } func (c *cancelCtx) Err() error { c.mu.Lock() defer c.mu.Unlock() return c.err } func (c *cancelCtx) cancel(removeFromParent bool, err error) { if err == nil { panic("context: internal error: missing cancel error") } c.mu.Lock() if c.err != nil { c.mu.Unlock() return // already canceled } c.err = err if c.done == nil { c.done = closedchan } else { close(c.done) } for child := range c.children { // NOTE: acquiring the child's lock while holding parent's lock. child.cancel(false, err) } c.children = nil c.mu.Unlock() if removeFromParent { removeChild(c.Context, c) } } type canceler interface { cancel(removeFromParent bool, err error) } var closedchan = make(chan struct{}) func init() { close(closedchan) } ``` 5. context.WithDeadline() WithDeadline函数返回一个带有截止时间的Context,当截止时间到达或者调用CancelFunc时,Context的Done通道将被关闭。 ```go func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { // The current deadline is already sooner than the new one. return WithCancel(parent) } c := &timerCtx{ cancelCtx: newCancelCtx(parent), deadline: deadline, } propagateCancel(parent, c) d := c.deadline.Sub(time.Now()) if d <= 0 { c.cancel(true, DeadlineExceeded) // deadline has already passed return c, func() { c.cancel(true, Canceled) } } c.mu.Lock() defer c.mu.Unlock() if c.err == nil { c.timer = time.AfterFunc(d, func() { c.cancel(true, DeadlineExceeded) }) } return c, func() { c.cancel(true, Canceled) } } type timerCtx struct { cancelCtx deadline time.Time mu sync.Mutex // protects timer and err timer *time.Timer err error } func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { return c.deadline, true } func (c *timerCtx) cancel(removeFromParent bool, err error) { c.cancelCtx.cancel(false, err) // propagate the cancel first c.mu.Lock() if c.timer != nil { c.timer.Stop() c.timer = nil } c.err = err c.mu.Unlock() if removeFromParent { removeChild(c.cancelCtx.Context, c) } } ``` 6. context.WithTimeout() WithTimeout函数返回一个带有超时时间的Context,当超时时间到达或者调用CancelFunc时,Context的Done通道将被关闭。 ```go func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } ``` 7. context.WithValue() WithValue函数返回一个带有键值对数据的Context,这个数据可以跨越多个API边界和Goroutine传递,而不需要显式地传递。 ```go func WithValue(parent Context, key, val interface{}) Context { if key == nil { panic("nil key") } if val == nil { panic("nil value") } return &valueCtx{parent, key, val} } type valueCtx struct { Context key, val interface{} } func (c *valueCtx) Value(key interface{}) interface{} { if c.key == key { return c.val } return c.Context.Value(key) } ``` 以上就是Context包的源码分析。Context包提供了一种简单而强大的机制来传递请求/值和取消信号,可以用于管理并发访问、超时控制和错误处理等场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值