Netty源码(五)NioEventLoop对其他任务的处理

Nio对其他任务的处理

任务执行

run

首先回到NioEventLoop的run方法

if (ioRatio == 100) {
	// 没有指定处理io事件占所有执行时间的比例
    try {
        processSelectedKeys();
    } finally {
        // Ensure we always run tasks.
        runAllTasks();
    }
} else {
	// 指定了处理io事件占所有执行时间的比例
    final long ioStartTime = System.nanoTime();
    try {
        processSelectedKeys();
    } finally {
        // Ensure we always run tasks.
        final long ioTime = System.nanoTime() - ioStartTime;
        runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
    }
}

runAllTasks

可以看到最终都会调用runAllTasks方法

protected boolean runAllTasks(long timeoutNanos) {
	// 从定时任务队列中获取待执行任务
    fetchFromScheduledTaskQueue();
    // 从任务队头获取执行任务
    Runnable task = pollTask();
    // 如果队列中没有任务,那么执行运行完所有任务的回调
    if (task == null) {
    	// 回调
        afterRunningAllTasks();
        return false;
    }

	// 计算执行deadline,当到达这个时间,将会跳出此次循环,不再执行任务
    final long deadline = ScheduledFutureTask.nanoTime() + timeoutNanos;
    long runTasks = 0;
    long lastExecutionTime;
    for (;;) {
    	// 调用任务的run方法
        safeExecute(task);

        runTasks ++;

        // Check timeout every 64 tasks because nanoTime() is relatively expensive.
        // XXX: Hard-coded value - will make it configurable if it is really a problem.
        // 每64个任务判断一下是否到了deadline
        if ((runTasks & 0x3F) == 0) {
            lastExecutionTime = ScheduledFutureTask.nanoTime();
            if (lastExecutionTime >= deadline) {
                break;
            }
        }
		
		// 从任务队列中取出新的任务
        task = pollTask();
        if (task == null) {
            lastExecutionTime = ScheduledFutureTask.nanoTime();
            break;
        }
    }
	
	// 执行回调
    afterRunningAllTasks();
    this.lastExecutionTime = lastExecutionTime;
    return true;
}

fetchFromSchedeuledTaskQueue

从定时任务队列中获取到期任务,然后添加到任务队列中
如果添加失败,将任务重新添加会定时任务队列

private boolean fetchFromScheduledTaskQueue() {
    long nanoTime = AbstractScheduledEventExecutor.nanoTime();
    // 从定时任务队列的头部获取当前已经到达deadline的定时任务
    Runnable scheduledTask  = pollScheduledTask(nanoTime);
    while (scheduledTask != null) {
    	// 尝试将到达deadline的定时任务添加到一般任务队列的末尾
        if (!taskQueue.offer(scheduledTask)) {
            // No space left in the task queue add it back to the scheduledTaskQueue so we pick it up again.
            // 如果添加失败,将该任务重新添加到定时任务队列中
            scheduledTaskQueue().add((ScheduledFutureTask<?>) scheduledTask);
            return false;
        }
        // 继续从定时任务队列的头部取出到了deadline的定时任务
        scheduledTask  = pollScheduledTask(nanoTime);
    }
    return true;
}

下面看下是如何从定时任务队列中取出任务的,可以看到代码比较简单,就是获取定时任务队里头部的任务,然后判断其deadline是否到期

protected final Runnable pollScheduledTask(long nanoTime) {
    assert inEventLoop();

    Queue<ScheduledFutureTask<?>> scheduledTaskQueue = this.scheduledTaskQueue;
    ScheduledFutureTask<?> scheduledTask = scheduledTaskQueue == null ? null : scheduledTaskQueue.peek();
    if (scheduledTask == null) {
        return null;
    }

    if (scheduledTask.deadlineNanos() <= nanoTime) {
        scheduledTaskQueue.remove();
        return scheduledTask;
    }
    return null;
}

pollTask

接下来看下如何从任务队列中取出接下来要执行的任务

protected Runnable pollTask() {
    assert inEventLoop();
    return pollTaskFrom(taskQueue);
}
protected static Runnable pollTaskFrom(Queue<Runnable> taskQueue) {
	// 从任务队列中跳过唤醒任务
    for (;;) {
        Runnable task = taskQueue.poll();
        if (task == WAKEUP_TASK) {
            continue;
        }
        return task;
    }
}

afterRunningAllTasks

当执行完任务队列中的所有任务或者deadline到了的时候,会执行afterRunningAllTasks回调
afterRunningAllTasks由SingleThreadEventExecutor的子类来进行实现
下面看下子类SingleTheadEventLoop的实现,比较简单,就是从tailQueue这个任务队列中获取任务然后执行

protected void afterRunningAllTasks() {
    runAllTasksFrom(tailTasks);
}
protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
    Runnable task = pollTaskFrom(taskQueue);
    if (task == null) {
        return false;
    }
    for (;;) {
        safeExecute(task);
        task = pollTaskFrom(taskQueue);
        if (task == null) {
            return true;
        }
    }
}

定时任务添加

首先Netty中用来代表定时任务的类ScheduledFutureTask

ScheduledFutureTask

重要属性
// 递增的任务编号
private static final AtomicLong nextTaskId = new AtomicLong();
// 开始时间
private static final long START_TIME = System.nanoTime();
// 当前任务的任务编号
private final long id = nextTaskId.getAndIncrement();
// deadline时间
private long deadlineNanos;
/* 0 - no repeat, >0 - repeat at fixed rate, <0 - repeat with fixed delay */
// 0 不需要重复
// >0 需要重复,并且按照任务的开始的时间保持一定间隔进行重复执行
// <0 需要重复,并且按照任务的结束时间保持一定间隔重复执行
private final long periodNanos;
构造方法
ScheduledFutureTask(
            AbstractScheduledEventExecutor executor,
            Callable<V> callable, long nanoTime, long period) {

    super(executor, callable);
    if (period == 0) {
        throw new IllegalArgumentException("period: 0 (expected: != 0)");
    }
    // deadlineNanos是相对当前时间的相对时间
    deadlineNanos = nanoTime;
    periodNanos = period;
}
nanoTime

计算当前系统时间和开始时间的间隔

static long nanoTime() {
    return System.nanoTime() - START_TIME;
}
compareTo
public int compareTo(Delayed o) {
    if (this == o) {
        return 0;
    }

	// 首先比较到期时间,到期时间更近的排在前面
	// 然后比较id,id小的排在前面
    ScheduledFutureTask<?> that = (ScheduledFutureTask<?>) o;
    long d = deadlineNanos() - that.deadlineNanos();
    if (d < 0) {
        return -1;
    } else if (d > 0) {
        return 1;
    } else if (id < that.id) {
        return -1;
    } else if (id == that.id) {
        throw new Error();
    } else {
        return 1;
    }
}
delayNanos
public long delayNanos() {
  // 计算当前还有多少时间到达deadline
  // deadlineNanos + START_TIME - current
  return Math.max(0, deadlineNanos() - nanoTime());
}

public long delayNanos(long currentTimeNanos) {
	// deadline + START_TIME - current
	// 指定时间距离deadline还有多少时间
    return Math.max(0, deadlineNanos() - (currentTimeNanos - START_TIME));
}
run

下面看下是如何执行的,这里的实现比较巧妙,当任务执行完毕后,如果判断当前任务仍然需要执行,会将自己添加到executor的定时任务队列中

public void run() {
   // 判断当前线程是否是eventLoop绑定的线程
   assert executor().inEventLoop();
   try {
   	   // 当前任务不需要重复
       if (periodNanos == 0) {
       		// 将当前任务的状态设置为不可取消f
           if (setUncancellableInternal()) {
           	  // 执行任务
               V result = task.call();
               // 如果result不为null,将任务的状态设置为返回值,否则设置为SUCCESS
               // 并且回调listener
               setSuccessInternal(result);
           }
       } else {
           // check if is done as it may was cancelled
           // 如果任务没有取消
           if (!isCancelled()) {
           		// 执行任务
               task.call();
               // 判断executor没有关闭
               if (!executor().isShutdown()) {
                   long p = periodNanos;
                   // 如果p>0,代表需要重复,并且按照任务的开始时间以一定间隔重复执行
                   if (p > 0) {
                       deadlineNanos += p;
                   } else {
                   	   // 如果p<0,代表需要重复,并且按照任务的结束时间
                   	   // deadlineNanos = (current - p) - START_TIME,相当于当前时间延迟-p nano执行
                       deadlineNanos = nanoTime() - p;
                   }
                   // 如果当前任务没有取消,将任务添加到executor的定时任务队列中
                   if (!isCancelled()) {
                       // scheduledTaskQueue can never be null as we lazy init it before submit the task!
                       Queue<ScheduledFutureTask<?>> scheduledTaskQueue =
                               ((AbstractScheduledEventExecutor) executor()).scheduledTaskQueue;
                       assert scheduledTaskQueue != null;
                       scheduledTaskQueue.add(this);
                   }
               }
           }
       }
   } catch (Throwable cause) {
       setFailureInternal(cause);
   }
}
cancel

一共有两个版本的cancel,都会取消任务的执行,cancel会另外将任务从定时任务队列中移除

public boolean cancel(boolean mayInterruptIfRunning) {
    boolean canceled = super.cancel(mayInterruptIfRunning);
    if (canceled) {
        ((AbstractScheduledEventExecutor) executor()).removeScheduled(this);
    }
    return canceled;
}

boolean cancelWithoutRemove(boolean mayInterruptIfRunning) {
    return super.cancel(mayInterruptIfRunning);
}

AbstractScheduledEventExecutor

重要属性
// 指定如何对定时任务队列中的任务排序
private static final Comparator<ScheduledFutureTask<?>> SCHEDULED_FUTURE_TASK_COMPARATOR =
            new Comparator<ScheduledFutureTask<?>>() {
                @Override
                public int compare(ScheduledFutureTask<?> o1, ScheduledFutureTask<?> o2) {
                    return o1.compareTo(o2);
                }
            };
// 定时任务队列
PriorityQueue<ScheduledFutureTask<?>> scheduledTaskQueue;
schedule
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
    ObjectUtil.checkNotNull(callable, "callable");
    ObjectUtil.checkNotNull(unit, "unit");
    if (delay < 0) {
        delay = 0;
    }
    validateScheduled0(delay, unit);
	
	// 使用给定的参数创建一个ScheduledFutureTask
    return schedule(new ScheduledFutureTask<V>(
            this, callable, ScheduledFutureTask.deadlineNanos(unit.toNanos(delay))));
}
<V> ScheduledFuture<V> schedule(final ScheduledFutureTask<V> task) {
	// 如果当前线程和eventLoop绑定的线程是同一个,那么将定时任务直接添加到定时任务队列中
    if (inEventLoop()) {
        scheduledTaskQueue().add(task);
    } else {
    	// 如果线程不一致,通过提交任务的方法来进行添加
        execute(new Runnable() {
            @Override
            public void run() {
                scheduledTaskQueue().add(task);
            }
        });
    }

    return task;
}

普通任务添加

这里看下SingleThreadEventExecutor的execute方法

public void execute(Runnable task) {
    if (task == null) {
        throw new NullPointerException("task");
    }

    boolean inEventLoop = inEventLoop();
    // 将待执行任务添加到任务队列中
    addTask(task);
    if (!inEventLoop) {
        startThread();
        if (isShutdown() && removeTask(task)) {
            reject();
        }
    }

    if (!addTaskWakesUp && wakesUpForTask(task)) {
        wakeup(inEventLoop);
    }
}
protected void addTask(Runnable task) {
    if (task == null) {
        throw new NullPointerException("task");
    }
    if (!offerTask(task)) {
        reject(task);
    }
}
final boolean offerTask(Runnable task) {
   if (isShutdown()) {
       reject();
   }
   return taskQueue.offer(task);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值