精华内容
下载资源
问答
  • 分省定时将销号数据放到SFTP服务器上,我需要开发定时任务去解析文件。因为是多省份,服务器、文件名规则、数据规则都不一定,所以要做成可配置是有一定难度的。数据规则这块必须强烈要求统一,服务器、文件名规则都...

    400400a2aec0d607d2a94b4d5c90800f.png

    一、前言

      上周工作遇到了一个需求,同步多个省份销号数据,解绑微信粉丝。分省定时将销号数据放到SFTP服务器上,我需要开发定时任务去解析文件。因为是多省份,服务器、文件名规则、数据规则都不一定,所以要做成可配置是有一定难度的。数据规则这块必须强烈要求统一,服务器、文件名规则都可以从配置中心去读。每新增一个省份的配置,后台感知到后,动态生成定时任务。

    二、Springboot引入定时任务核心配置

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Import(SchedulingConfiguration.class)
    @Documented
    public @interface EnableScheduling {
    
    }
    
    @Configuration
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public class SchedulingConfiguration {
    
        @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
            return new ScheduledAnnotationBeanPostProcessor();
        }
    
    }

      接下来主要看一下这个核心后置处理器:ScheduledAnnotationBeanPostProcessor 。

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof AopInfrastructureBean || bean instanceof TaskScheduler ||
                bean instanceof ScheduledExecutorService) {
            // Ignore AOP infrastructure such as scoped proxies.
            return bean;
        }
    
        Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
        if (!this.nonAnnotatedClasses.contains(targetClass)) {
            Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
                    (MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
                        Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
                                method, Scheduled.class, Schedules.class);
                        return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
                    });
            if (annotatedMethods.isEmpty()) {
                this.nonAnnotatedClasses.add(targetClass);
                if (logger.isTraceEnabled()) {
                    logger.trace("No @Scheduled annotations found on bean class: " + targetClass);
                }
            }
            else {
                // Non-empty set of methods
                annotatedMethods.forEach((method, scheduledMethods) ->
                        scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean)));
                if (logger.isTraceEnabled()) {
                    logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName +
                            "': " + annotatedMethods);
                }
            }
        }
        return bean;
    }

      1、处理Scheduled注解,通过ScheduledTaskRegistrar注册定时任务。

    private void finishRegistration() {
        if (this.scheduler != null) {
            this.registrar.setScheduler(this.scheduler);
        }
    
        if (this.beanFactory instanceof ListableBeanFactory) {
            Map<String, SchedulingConfigurer> beans =
                    ((ListableBeanFactory) this.beanFactory).getBeansOfType(SchedulingConfigurer.class);
            List<SchedulingConfigurer> configurers = new ArrayList<>(beans.values());
            AnnotationAwareOrderComparator.sort(configurers);
            for (SchedulingConfigurer configurer : configurers) {
                configurer.configureTasks(this.registrar);
            }
        }
    
        if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
            Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type");
            try {
                // Search for TaskScheduler bean...
                this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, false));
            }
            catch (NoUniqueBeanDefinitionException ex) {
                logger.trace("Could not find unique TaskScheduler bean", ex);
                try {
                    this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, true));
                }
                catch (NoSuchBeanDefinitionException ex2) {
                    if (logger.isInfoEnabled()) {
                        logger.info("More than one TaskScheduler bean exists within the context, and " +
                                "none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' " +
                                "(possibly as an alias); or implement the SchedulingConfigurer interface and call " +
                                "ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: " +
                                ex.getBeanNamesFound());
                    }
                }
            }
            catch (NoSuchBeanDefinitionException ex) {
                logger.trace("Could not find default TaskScheduler bean", ex);
                // Search for ScheduledExecutorService bean next...
                try {
                    this.registrar.setScheduler(resolveSchedulerBean(this.beanFactory, ScheduledExecutorService.class, false));
                }
                catch (NoUniqueBeanDefinitionException ex2) {
                    logger.trace("Could not find unique ScheduledExecutorService bean", ex2);
                    try {
                        this.registrar.setScheduler(resolveSchedulerBean(this.beanFactory, ScheduledExecutorService.class, true));
                    }
                    catch (NoSuchBeanDefinitionException ex3) {
                        if (logger.isInfoEnabled()) {
                            logger.info("More than one ScheduledExecutorService bean exists within the context, and " +
                                    "none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' " +
                                    "(possibly as an alias); or implement the SchedulingConfigurer interface and call " +
                                    "ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: " +
                                    ex2.getBeanNamesFound());
                        }
                    }
                }
                catch (NoSuchBeanDefinitionException ex2) {
                    logger.trace("Could not find default ScheduledExecutorService bean", ex2);
                    // Giving up -> falling back to default scheduler within the registrar...
                    logger.info("No TaskScheduler/ScheduledExecutorService bean found for scheduled processing");
                }
            }
        }
    
        this.registrar.afterPropertiesSet();
    }

      1、通过一系列的SchedulingConfigurer动态配置ScheduledTaskRegistrar。

      2、向ScheduledTaskRegistrar注册一个TaskScheduler(用于对Runnable的任务进行调度,它包含有多种触发规则)。

      3、registrar.afterPropertiesSet(),在这开始安排所有的定时任务开始执行了。

    protected void scheduleTasks() {
        if (this.taskScheduler == null) {
            this.localExecutor = Executors.newSingleThreadScheduledExecutor();
            this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
        }
        if (this.triggerTasks != null) {
            for (TriggerTask task : this.triggerTasks) {
                addScheduledTask(scheduleTriggerTask(task));
            }
        }
        if (this.cronTasks != null) {
            for (CronTask task : this.cronTasks) {
                addScheduledTask(scheduleCronTask(task));
            }
        }
        if (this.fixedRateTasks != null) {
            for (IntervalTask task : this.fixedRateTasks) {
                addScheduledTask(scheduleFixedRateTask(task));
            }
        }
        if (this.fixedDelayTasks != null) {
            for (IntervalTask task : this.fixedDelayTasks) {
                addScheduledTask(scheduleFixedDelayTask(task));
            }
        }
    }

      1、TriggerTask:动态定时任务。通过Trigger#nextExecutionTime 给定的触发上下文确定下一个执行时间。

      2、CronTask:动态定时任务,TriggerTask子类。通过cron表达式确定的时间触发下一个任务执行。

      3、IntervalTask:一定时间延迟之后,周期性执行的任务。

      4、taskScheduler 如果为空,默认是ConcurrentTaskScheduler,并使用默认单线程的ScheduledExecutor。

    三、主要看一下CronTask工作原理

    ScheduledTaskRegistrar.java
    @Nullable
    public ScheduledTask scheduleCronTask(CronTask task) {
        ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);
        boolean newTask = false;
        if (scheduledTask == null) {
            scheduledTask = new ScheduledTask(task);
            newTask = true;
        }
        if (this.taskScheduler != null) {
            scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger());
        }
        else {
            addCronTask(task);
            this.unresolvedTasks.put(task, scheduledTask);
        }
        return (newTask ? scheduledTask : null);
    }
    
    ConcurrentTaskScheduler.java
    @Override
    @Nullable
    public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
        try {
            if (this.enterpriseConcurrentScheduler) {
                return new EnterpriseConcurrentTriggerScheduler().schedule(decorateTask(task, true), trigger);
            }
            else {
                ErrorHandler errorHandler =
                        (this.errorHandler != null ? this.errorHandler : TaskUtils.getDefaultErrorHandler(true));
                return new ReschedulingRunnable(task, trigger, this.scheduledExecutor, errorHandler).schedule();
            }
        }
        catch (RejectedExecutionException ex) {
            throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, ex);
        }
    }
    
    ReschedulingRunnable.java
    @Nullable
    public ScheduledFuture<?> schedule() {
        synchronized (this.triggerContextMonitor) {
            this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext);
            if (this.scheduledExecutionTime == null) {
                return null;
            }
            long initialDelay = this.scheduledExecutionTime.getTime() - System.currentTimeMillis();
            this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
            return this;
        }
    }
    
    private ScheduledFuture<?> obtainCurrentFuture() {
        Assert.state(this.currentFuture != null, "No scheduled future");
        return this.currentFuture;
    }
    
    @Override
    public void run() {
        Date actualExecutionTime = new Date();
        super.run();
        Date completionTime = new Date();
        synchronized (this.triggerContextMonitor) {
            Assert.state(this.scheduledExecutionTime != null, "No scheduled execution");
            this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
            if (!obtainCurrentFuture().isCancelled()) {
                schedule();
            }
        }
    }

      1、最终将task和trigger都封装到了ReschedulingRunnable中。

      2、ReschedulingRunnable实现了任务重复调度(schedule方法中调用调度器executor并传入自身对象,executor会调用run方法,run方法又调用了schedule方法)。

      3、ReschedulingRunnable schedule方法加了同步锁,只能有一个线程拿到下次执行时间并加入执行器的调度。

      4、不同的ReschedulingRunnable对象之间在线程池够用的情况下是不会相互影响的,也就是说满足线程池的条件下,TaskScheduler的schedule方法的多次调用是可以交叉执行的。

    ScheduledThreadPoolExecutor.java
    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        RunnableScheduledFuture<?> t = decorateTask(command,
            new ScheduledFutureTask<Void>(command, null,
                                          triggerTime(delay, unit)));
        delayedExecute(t);
        return t;
    }
    
    
    private void delayedExecute(RunnableScheduledFuture<?> task) {
        if (isShutdown())
            reject(task);
        else {
            super.getQueue().add(task);
            if (isShutdown() &&
                !canRunInCurrentRunState(task.isPeriodic()) &&
                remove(task))
                task.cancel(false);
            else
                ensurePrestart();
        }
    }

      ScheduledFutureTask 工作原理如下图所示【太懒了,不想画图了,盗图一张】。

    a0251698eb27a0716e7aae85264fb8c2.png

      1、ScheduledFutureTask会放入优先阻塞队列:ScheduledThreadPoolExecutor.DelayedWorkQueue(二叉最小堆实现)

      2、上图中的Thread对象即ThreadPoolExecutor.Worker,实现了Runnable接口

    /**
     * Creates with given first task and thread from ThreadFactory.
     * @param firstTask the first task (null if none)
     */
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }
    
    /** Delegates main run loop to outer runWorker  */
    public void run() {
        runWorker(this);
    }

      1、Worker中维护了Thread对象,Thread对象的Runnable实例即Worker自身

      2、ThreadPoolExecutor#addWorker方法中会创建Worker对象,然后拿到Worker中的thread实例并start,这样就创建了线程池中的一个线程实例

      3、Worker的run方法会调用ThreadPoolExecutor#runWorker方法,这才是任务最终被执行的地方,该方法示意如下

      (1)首先取传入的task执行,如果task是null,只要该线程池处于运行状态,就会通过getTask方法从workQueue中取任务。ThreadPoolExecutor的execute方法会在无法产生core线程的时候向  workQueue队列中offer任务。
    getTask方法从队列中取task的时候会根据相关配置决定是否阻塞和阻塞多久。如果getTask方法结束,返回的是null,runWorker循环结束,执行processWorkerExit方法。
    至此,该线程结束自己的使命,从线程池中“消失”。
      (2)在开始执行任务之前,会调用Worker的lock方法,目的是阻止task正在被执行的时候被interrupt,通过调用clearInterruptsForTaskRun方法来保证的(后面可以看一下这个方法),该线程没有自己的interrupt set了。
      (3)beforeExecute和afterExecute方法用于在执行任务前后执行一些自定义的操作,这两个方法是空的,留给继承类去填充功能。
    我们可以在beforeExecute方法中抛出异常,这样task不会被执行,而且在跳出该循环的时候completedAbruptly的值是true,表示the worker died due to user exception,会用decrementWorkerCount调整wc。
      (4)因为Runnable的run方法不能抛出Throwables异常,所以这里重新包装异常然后抛出,抛出的异常会使当当前线程死掉,可以在afterExecute中对异常做一些处理。
      (5)afterExecute方法也可能抛出异常,也可能使当前线程死掉。

    四、动态创建定时任务

      TaskConfiguration 配置类

    @Configuration
    @EnableScheduling
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public class TaskConfiguration {
    
        @Bean(name = ScheduledAnnotationBeanPostProcessor.DEFAULT_TASK_SCHEDULER_BEAN_NAME)
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public ScheduledExecutorService scheduledAnnotationProcessor() {
            return Executors.newScheduledThreadPool(5, new DefaultThreadFactory());
        }
    
        private static class DefaultThreadFactory implements ThreadFactory {
            private static final AtomicInteger poolNumber = new AtomicInteger(1);
            private final ThreadGroup group;
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            private final String namePrefix;
    
            DefaultThreadFactory() {
                SecurityManager s = System.getSecurityManager();
                group = (s != null) ? s.getThreadGroup() :
                        Thread.currentThread().getThreadGroup();
                namePrefix = "pool-" +
                        poolNumber.getAndIncrement() +
                        "-schedule-";
            }
    
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(group, r,
                        namePrefix + threadNumber.getAndIncrement(),
                        0);
                if (t.isDaemon()) {
                    t.setDaemon(false);
                }
                if (t.getPriority() != Thread.NORM_PRIORITY) {
                    t.setPriority(Thread.NORM_PRIORITY);
                }
                return t;
            }
        }
    }

      1、保证ConcurrentTaskScheduler不使用默认单线程的ScheduledExecutor,而是corePoolSize=5的线程池

      2、自定义线程池工厂类

      DynamicTask 动态定时任务

    @Configuration
    public class DynamicTask implements SchedulingConfigurer {
        private static Logger LOGGER = LoggerFactory.getLogger(DynamicTask.class);
    
        private static final ExecutorService es = new ThreadPoolExecutor(10, 20,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(10),
                new DynamicTaskConsumeThreadFactory());
    
    
        private volatile ScheduledTaskRegistrar registrar;
        private final ConcurrentHashMap<String, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<>();
        private final ConcurrentHashMap<String, CronTask> cronTasks = new ConcurrentHashMap<>();
    
        private volatile List<TaskConstant> taskConstants = Lists.newArrayList();
    
        @Override
        public void configureTasks(ScheduledTaskRegistrar registrar) {
            this.registrar = registrar;
            this.registrar.addTriggerTask(() -> {
                        if (!CollectionUtils.isEmpty(taskConstants)) {
                            LOGGER.info("检测动态定时任务列表...");
                            List<TimingTask> tts = new ArrayList<>();
                            taskConstants
                                    .forEach(taskConstant -> {
                                        TimingTask tt = new TimingTask();
                                        tt.setExpression(taskConstant.getCron());
                                        tt.setTaskId("dynamic-task-" + taskConstant.getTaskId());
                                        tts.add(tt);
                                    });
                            this.refreshTasks(tts);
                        }
                    }
                    , triggerContext -> new PeriodicTrigger(5L, TimeUnit.SECONDS).nextExecutionTime(triggerContext));
        }
    
    
        public List<TaskConstant> getTaskConstants() {
            return taskConstants;
        }
    
        private void refreshTasks(List<TimingTask> tasks) {
            //取消已经删除的策略任务
            Set<String> taskIds = scheduledFutures.keySet();
            for (String taskId : taskIds) {
                if (!exists(tasks, taskId)) {
                    scheduledFutures.get(taskId).cancel(false);
                }
            }
            for (TimingTask tt : tasks) {
                String expression = tt.getExpression();
                if (StringUtils.isBlank(expression) || !CronSequenceGenerator.isValidExpression(expression)) {
                    LOGGER.error("定时任务DynamicTask cron表达式不合法: " + expression);
                    continue;
                }
                //如果配置一致,则不需要重新创建定时任务
                if (scheduledFutures.containsKey(tt.getTaskId())
                        && cronTasks.get(tt.getTaskId()).getExpression().equals(expression)) {
                    continue;
                }
                //如果策略执行时间发生了变化,则取消当前策略的任务
                if (scheduledFutures.containsKey(tt.getTaskId())) {
                    scheduledFutures.remove(tt.getTaskId()).cancel(false);
                    cronTasks.remove(tt.getTaskId());
                }
                CronTask task = new CronTask(tt, expression);
                ScheduledFuture<?> future = registrar.getScheduler().schedule(task.getRunnable(), task.getTrigger());
                cronTasks.put(tt.getTaskId(), task);
                scheduledFutures.put(tt.getTaskId(), future);
            }
        }
    
        private boolean exists(List<TimingTask> tasks, String taskId) {
            for (TimingTask task : tasks) {
                if (task.getTaskId().equals(taskId)) {
                    return true;
                }
            }
            return false;
        }
    
        @PreDestroy
        public void destroy() {
            this.registrar.destroy();
        }
    
        public static class TaskConstant {
            private String cron;
            private String taskId;
    
            public String getCron() {
                return cron;
            }
    
            public void setCron(String cron) {
                this.cron = cron;
            }
    
            public String getTaskId() {
                return taskId;
            }
    
            public void setTaskId(String taskId) {
                this.taskId = taskId;
            }
        }
    
        private class TimingTask implements Runnable {
            private String expression;
    
            private String taskId;
    
            public String getTaskId() {
                return taskId;
            }
    
            public void setTaskId(String taskId) {
                this.taskId = taskId;
            }
    
            @Override
            public void run() {
                //设置队列大小10
                LOGGER.error("当前CronTask: " + this);
                DynamicBlockingQueue queue = new DynamicBlockingQueue(3);
                es.submit(() -> {
                    while (!queue.isDone() || !queue.isEmpty()) {
                        try {
                            String content = queue.poll(500, TimeUnit.MILLISECONDS);
                            if (StringUtils.isBlank(content)) {
                                return;
                            }
                            LOGGER.info("DynamicBlockingQueue 消费:" + content);
                            TimeUnit.MILLISECONDS.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
    
                //队列放入数据
                for (int i = 0; i < 5; ++i) {
                    try {
                        queue.put(String.valueOf(i));
                        LOGGER.info("DynamicBlockingQueue 生产:" + i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                queue.setDone(true);
            }
    
            public String getExpression() {
                return expression;
            }
    
            public void setExpression(String expression) {
                this.expression = expression;
            }
    
            @Override
            public String toString() {
                return ReflectionToStringBuilder.toString(this
                        , ToStringStyle.JSON_STYLE
                        , false
                        , false
                        , TimingTask.class);
            }
    
        }
    
        /**
         * 队列消费线程工厂类
         */
        private static class DynamicTaskConsumeThreadFactory implements ThreadFactory {
            private static final AtomicInteger poolNumber = new AtomicInteger(1);
            private final ThreadGroup group;
            private final AtomicInteger threadNumber = new AtomicInteger(1);
            private final String namePrefix;
    
            DynamicTaskConsumeThreadFactory() {
                SecurityManager s = System.getSecurityManager();
                group = (s != null) ? s.getThreadGroup() :
                        Thread.currentThread().getThreadGroup();
                namePrefix = "pool-" +
                        poolNumber.getAndIncrement() +
                        "-dynamic-task-";
            }
    
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(group, r,
                        namePrefix + threadNumber.getAndIncrement(),
                        0);
                if (t.isDaemon()) {
                    t.setDaemon(false);
                }
                if (t.getPriority() != Thread.NORM_PRIORITY) {
                    t.setPriority(Thread.NORM_PRIORITY);
                }
                return t;
            }
        }
    
        private static class DynamicBlockingQueue extends LinkedBlockingQueue<String> {
            DynamicBlockingQueue(int capacity) {
                super(capacity);
            }
    
    
            private volatile boolean done = false;
    
            public boolean isDone() {
                return done;
            }
    
            public void setDone(boolean done) {
                this.done = done;
            }
        }
    }

      1、taskConstants 动态任务列表

      2、ScheduledTaskRegistrar#addTriggerTask 添加动态周期定时任务,检测动态任务列表的变化

    CronTask task = new CronTask(tt, expression);
    ScheduledFuture<?> future = registrar.getScheduler().schedule(task.getRunnable(), task.getTrigger());
    cronTasks.put(tt.getTaskId(), task);
    scheduledFutures.put(tt.getTaskId(), future);

      3、动态创建cron定时任务,拿到ScheduledFuture实例并缓存起来

      4、在刷新任务列表时,通过缓存的ScheduledFuture实例和CronTask实例,来决定是否取消、移除失效的动态定时任务。

      DynamicTaskTest 动态定时任务测试类

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class DynamicTaskTest {
    
        @Autowired
        private DynamicTask dynamicTask;
    
        @Test
        public void test() throws InterruptedException {
            List<DynamicTask.TaskConstant> taskConstans = dynamicTask.getTaskConstants();
            DynamicTask.TaskConstant taskConstant = new DynamicTask.TaskConstant();
            taskConstant.setCron("0/5 * * * * ?");
            taskConstant.setTaskId("test1");
            taskConstans.add(taskConstant);
    
    
            DynamicTask.TaskConstant taskConstant1 = new DynamicTask.TaskConstant();
            taskConstant1.setCron("0/5 * * * * ?");
            taskConstant1.setTaskId("test2");
            taskConstans.add(taskConstant1);
    
            DynamicTask.TaskConstant taskConstant2 = new DynamicTask.TaskConstant();
            taskConstant2.setCron("0/5 * * * * ?");
            taskConstant2.setTaskId("test3");
            taskConstans.add(taskConstant2);
    
            TimeUnit.SECONDS.sleep(40);
            //移除并添加新的配置
            taskConstans.remove(taskConstans.size() - 1);
            DynamicTask.TaskConstant taskConstant3 = new DynamicTask.TaskConstant();
            taskConstant3.setCron("0/5 * * * * ?");
            taskConstant3.setTaskId("test4");
            taskConstans.add(taskConstant3);
    //
            TimeUnit.MINUTES.sleep(50);
        }
    }
    展开全文
  • 这里写自定义目录标题SCHTASKS 任务定时关机和删除关机任务定时 关机 任务删除 关机 任务 SCHTASKS 任务定时关机和删除关机任务 SCHTASKS /parameter [arguments] 描述: 允许管理员创建、删除、查询、更改、运行和...

    SCHTASKS 任务定时关机和删除关机任务

    SCHTASKS /parameter [arguments]

    描述:
    允许管理员创建、删除、查询、更改、运行和中止本地或远程系统上的计划任务。

    参数列表:

    • /Create 创建新计划任务。
    • /Delete 删除计划任务。
    • /Query 显示所有计划任务。
    • /Change 更改计划任务属性。
    • /Run 按需运行计划任务。
    • /End 中止当前正在运行的计划任务。
    • /ShowSid 显示与计划的任务名称相应的安全标识符。
    • /? 显示此帮助消息。
      Examples:
        SCHTASKS 
        SCHTASKS /?
        SCHTASKS /Run /?
        SCHTASKS /End /?
        SCHTASKS /Create /?
        SCHTASKS /Delete /?
        SCHTASKS /Query  /?
        SCHTASKS /Change /?
        SCHTASKS /ShowSid /?
    

    定时 关机 任务

    win7 win10 都可以 不过要以管理员身份运行CMD下 执行下面的命令

    SCHTASKS /Create /tn "turnoff" /tr "shutdown -s -t 60" /sc DAILY /st 20:20
    
    

    删除 关机 任务

    win7 win10 都可以 不过要以管理员身份运行CMD下 执行下面的命令

    SCHTASKS /Delete /TN "turnoff" /F
    
    
    展开全文
  • 创建任务:schtasks/create/scdaily/tn"每晚关机"/tr"shutdown-s-t00"/st22:00 解除任务:schtasks/delete/tn"每晚关机"/f
    创建任务:schtasks /create /sc daily /tn "每晚关机" /tr "shutdown -s -t 00" /st 22:00
    
    解除任务:schtasks /delete /tn "每晚关机" /f

     

    展开全文
  • 你在网上找还真不是那么好找,下面我们用Windows计划任务设置:定时关机,而且,我还在计划任务中看到了几个不该有的计划任务。​打开:计划任务点击Cortana输入:计划任务,点击打开搜索处理的“计划任务”;也可以...

    定时关机其实是一个小功能,很多时候还真的需要它。你在网上找还真不是那么好找,下面我们用Windows计划任务设置:定时关机,而且,我还在计划任务中看到了几个不该有的计划任务。

    56c4b22ddc45e9fb7dc0134444f9eccb.png

    打开:计划任务

    点击Cortana输入:计划任务,点击打开搜索处理的“计划任务”;也可以在控制面板中找到“管理工具”,计划任务也在其中且还有其他工具。

    32bdd7576d3341b94d63b95079d1bb91.png

    打开计划任务后,会出现下图界面。然后点击:创建任务。

    e3dbed1b9f52a88f41b1bc0b96aa5b77.png

    创建:定时关机

    点击创建任务后弹出下图对话框,名称输入:定时关机(这个根据自身喜好输入)。

    bf6c191df1570dacff44f59f3c03dfda.png

    然后在选项卡点击“触发器”,在“触发器”页面点击“新建”,弹出下面对话框,这里就是你设置你想关机的时间,设置好时间后点击“确定”按钮。

    b630ac06f9eb1ca796df0b914ce3839e.png

    然后再点击选项卡中的“操作”,进入“操作”页面后点击“新建”,弹出下面对话框。

    1.在设置选项里面,设置“程序或脚本”,设置成和下图一致,也可以复制:“C:WindowsSystem32shutdown.exe”。

    2.设置“添加参数”:-s,如果不设置这个参数,关机操作是不能执行的,所以一定要设置。

    然后点击“确定”,定时关机就设置完成了。

    8ddd78d79b67c0e8ae40272e580c298a.png

    查看是否创建成功

    点击左侧的“任务计划程序库”,下图。可以看到“定时关机”已经有了,在“定时关机”项点击右键,可以编辑(属性里面)、运行、警用等;如果下一次你想定时关机,直接选中“定时关机”项,右键属性,编辑时间即可。

    75318d7cb7b33b05aca4792629ec5183.png

    上图中,除了“定时关机”项,其他几项是什么?看描述信息应该可以猜到是WPS和360压缩的定时任务,个人觉得没什么用可以禁用或删除。

    展开全文
  • windows设置定时关机

    2018-08-31 16:41:34
    创建定时关机任务: 点击“开始”按钮,输入cmd,按回车键。 输入at 10:00 /every:M,T,W,Th,F,S,Su shutdown –s –t 120  说明:10:00 为关机时间  M,T,W,Th,F,S,Su为周一到周日(可任意选择一天或多天) ...
  • 一、使用关机命令shutdown 命令提示符输入关机命令shutdown...任务触发器 希望任务何时开始:我是要每天要关机,这里我们选择了默认的“每天”。“下一步”, 每天设置关机时间晚上11点关机,这里我们修改第二个框中内
  • 定时关机

    2021-02-24 09:57:45
    1 打开“任务计划程序” 2 右键"任务计划程序(本地)" 3 选择“创建基本任务” 4 自定义程序名称,下一步 5 选择触发次数,下一步 ...11.1 点击任务计划程序库,找到添加的‘定时关机’ 11.2 右键删除 ...
  • 可以设置定时关机呀,预算好什么时候下载结束,然后设置定时关机就可以不用去管它了。那么怎样设置电脑定时关机呢?下面跟小编一起来看看吧。1、点击电脑屏幕左下角的开始按钮,在所有程序里依次选择选择附件---系统...
  • 电脑定时关机

    2019-05-12 00:12:34
    然后点击右边的“创建基本任务,然后在名称输入框后填写:定时关机,并点击下一步! 到触发器这里选择任务开始时间,小编这里以每天定时关机为例,点击下一步! 然后在这里输入定时关机的时间,点击下一步! 到启...
  • //创建关机计划任务 bool addShutDownJob(int hour,int min) { CString time; time.Format("%02d:%02d", hour, min); CString key; //空格不能随便添加 key.Format("schtasks /create /TN ShutdownPc /...
  • 在Win7、Win8或者Win10系统中,如果要实现电脑的自动定时关机,不需要借用任何的外部程序,直接系统自带的任务计划程序即可实现电脑的定时自动关机,支持设定电脑关机时间以及执行频率次数,如固定每天都执行电脑...
  • 方法一:利用计划程序步骤一:在开始菜单搜索框中...选中启动程序点击下一步步骤六:选择浏览,在文件夹中找到shutdown.exe并打开步骤七:点击完成,设置成功,电脑会按照你设定的定时关机END方法二:利用关机命令定...
  • 但是人又不能一直等到它运行完才离开,或者其他各种原因而不能马上关机,所以这就需要设置一下电脑自动关机了,方法有两个,今天先说第一种电脑定时自动关机的方法:添加计划任务1、在桌面计算机图标上点击鼠标右键...
  • ②在右边的操作中选择"创建基本任务",你可以在"任务名称"中填写你想填的名字,比如"定时关机". ③选择任务执行时间,每天都要定时关机的可以选择"每天";每个星期中有几天不需要关机的可以选…… 时间框里填写好...
  • Windows定时关机

    2016-01-28 16:12:32
    点击“任务计划程序”,然后在右边点击“创建基本任务”,随便填写个任务名称,比如定时关机,完了点击下一步 3.选择“一次”,点击下一步 4.设置开始时间,点击下一步 5.选择“启动程序”,点击下一步 ...
  • tid=665022&pid=9346020&page=1&extra=page%3D1#pid9346020 ...Win7如何添加任务计划‘定时关机’应用一:Win7计划任务创建消息提醒利用Win7任务计划我们可以常见一些消息系统功能,如...
  • 2、在右边的操作中选择【创建基本任务】,你可以在【任务名称】中填写你想填的名字,这里填写的是"定时关机";3、选择任务执行时间,对于每天都要定时关机的可以选择"每天";对于每个星期中有几天不需要关机的可以选择...
  • Win7 每天定时关机

    2015-05-09 10:20:41
    1. 创建任务计划1.1 打开:开始/所有程序/附件/系统工具/任务计划程序1.2 在右边的操作中选择”创建基本任务”,你可以在”任务名称”中填写你想填的名字,比如”定时关机”.1.3 选择任务执行时间,每天都要定时关机的...
  • bat批处理定时关机

    2017-06-29 21:08:04
    @echo off shutdown -a cls set /a aaa = 0  set /a guanji = 0 ...echo =========================请输入数字=============...echo 1:设置定时 2:查看已创建任务 3:删除任务 4:倒计时关机(分)5:取消倒计时关机
  • Win7定时关机

    2011-07-07 17:53:05
    计划任务(或任务计划程序)2、在打开的“任务计划程序”右侧的任务中点击“创建基本任务...”3、在名称后输入“定时关机”,点击下一步4、选择任务开始为“每天”,点击下一步5、在开始时间设置中,开始日期不动,...
  • win7定时关机

    2017-08-23 10:45:00
    菜单》附件》系统工具》任务计划程序》创建基本任务 alt+r》cmd》shutdown/? 查看相关参数 /l 注销 /s 关机 /r 重启 /g 重启,重启后,重新启动所有注册的应用程序 /a 中止系统系统关闭 /p ...
  • win10系统定时关机

    2018-11-09 19:57:30
    1、打开控制面板 2、打开管理工具 ...4、右击创建基本任务,填写名称和描述,下一步 5、创建开始时间 6、程序就填shutdown命令,参数就设置成-s -t 10,意为23点后的10秒执行关机. 7、设置完成  ...
  • 本文包含以下内容 前提条件 如何实现定时关闭虚拟机 ...Controller 机器上必须安装 Azure PowerShell,并且要在 ...配好 Azure PowerShell 以后,就可以用下面这个脚本创建定时关机任务。把下面的代码另存为一...
  • 1.右键我的电脑-管理 2.找到windows-点击创建任务 3.常规-输入名称-设置权限 4.触发器-新建 5.操作-新建-浏览-C:\Windows\System32\shutdown.exe\参数:-s 6.确定-重启计算机

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 144
精华内容 57
关键字:

创建定时关机任务