简体   繁体   English

如何在线程外停止计划任务/线程

[英]How to stop scheduled task/thread outside of thread

I'm trying to practice and learn more about multi-threading and scheduling tasks.我正在尝试练习和了解有关多线程和调度任务的更多信息。
I wrote a test program that mimics a scheduler I'm trying to implement in a bot and its behaving in a way I don't really understand.我编写了一个测试程序,该程序模仿了我试图在机器人中实现的调度程序,并且它的行为方式我并不真正理解。 Basically I created a task and scheduled it to run and I want it to be canceled after some event (in this instance, when count > 5).基本上我创建了一个任务并安排它运行,我希望它在某些事件之后被取消(在这种情况下,当计数 > 5 时)。
It seems to run indefinitely even though the count is over 5, but when I put in a line to sleep the main thread or print from it, it works as I'd expect it to.即使计数超过 5,它似乎也无限期地运行,但是当我放入一行以使主线程休眠或从中打印时,它会按我的预期工作。

Can someone why this is the case?有人可以为什么会这样吗?
It's as if like if there is no interaction with the main thread, it never hits the condition or just ignores it, but as soon as I put something in for the main thread to process, it checks the condition as well.就好像没有与主线程的交互,它永远不会达到条件或只是忽略它,但是一旦我将一些东西放入主线程进行处理,它也会检查条件。

public class Driver {
  public static void main(String[] args) throws InterruptedException {
    TestScheduler test = new TestScheduler();
    test.startScheduler();
  }
}


public class TestScheduler {
  private static ScheduledExecutorService ses;
  private static int count;

  public TestScheduler(){
    ses = Executors.newScheduledThreadPool(2);
    count = 0;
  }

  public void startScheduler() throws InterruptedException {
    System.out.println("startScheduler() thread: " + Thread.currentThread().getName());

    Runnable testTask = () -> {
      System.out.println(Thread.currentThread().getName() + ": count " + count++);
    };

    System.out.println("Starting test scheduler for 10s");
    ScheduledFuture<?> scheduledFuture = ses.scheduleAtFixedRate(testTask, 5, 1, TimeUnit.SECONDS);
    System.out.println("ScheduledFuture started...");

    while(true){
      // if any of the 2 lines below are uncommented, it works as I'd expect it to...
      //Thread.sleep(1000);
      //System.out.println(Thread.currentThread().getName() + ": count " + count);
      if (count > 5){
        System.out.println(Thread.currentThread().getName() + ": Cancelling scheduled task.");
        scheduledFuture.cancel(true);
        break;
      }
    }
    System.out.println("Ending test scheduler");
  }

Here is the output with Thread.sleep and println commented out:这是 output 与 Thread.sleep 和 println 注释掉:

startScheduler() thread: main
Starting test scheduler for 10s
ScheduledFuture started...
pool-1-thread-1: count 0
pool-1-thread-2: count 1
pool-1-thread-2: count 2
pool-1-thread-2: count 3
pool-1-thread-2: count 4
pool-1-thread-2: count 5
pool-1-thread-2: count 6
pool-1-thread-2: count 7
pool-1-thread-1: count 8
pool-1-thread-1: count 9
pool-1-thread-1: count 10
...

And with the 2 lines uncommented:并且没有注释 2 行:

startScheduler() thread: main
Starting test scheduler for 10s
ScheduledFuture started...
main: count 0
main: count 0
main: count 0
main: count 0
pool-1-thread-1: count 0
main: count 1
pool-1-thread-1: count 1
main: count 2
pool-1-thread-1: count 2
main: count 3
pool-1-thread-1: count 3
main: count 4
pool-1-thread-1: count 4
main: count 5
pool-1-thread-1: count 5
main: count 6
main: Cancelling scheduled task.
Ending test scheduler

If there are any resources to look at that can explain why the above scenario occurs and possibly one for an intro to multithreading I'd appreciate it.如果有任何资源可以解释为什么会发生上述情况,并且可能有一个用于介绍多线程的资源,我将不胜感激。

Also, is there an ideal way to handle cancelling threads outside of the thread in question, like having one dedicated to checking/managing the conditions?此外,是否有一种理想的方法来处理相关线程之外的取消线程,比如有一个专门用于检查/管理条件的方法?

Its happening due to race conditions while accessing count .它是由于访问count时的竞争条件而发生的。
2 threads are accessing this variable at the same time without any locks. 2 个线程同时访问这个变量,没有任何锁。
You can use an AtomicInteger to overcome this:您可以使用AtomicInteger来克服这个问题:

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class Driver {
  public static void main(String[] args) throws InterruptedException {
    TestScheduler test = new TestScheduler();
    test.startScheduler();
  }
}


class TestScheduler {
  private ScheduledExecutorService ses = Executors.newScheduledThreadPool(2);
  private AtomicInteger count = new AtomicInteger(0);

  public void startScheduler() throws InterruptedException {
    System.out.println("startScheduler() thread: " + Thread.currentThread().getName());

    Runnable testTask = () -> {
      System.out.println(Thread.currentThread().getName() + ": count " + count.getAndIncrement());
    };

    System.out.println("Starting test scheduler for 10s");
    ScheduledFuture<?> scheduledFuture = ses.scheduleAtFixedRate(testTask, 5, 1, TimeUnit.SECONDS);
    System.out.println("ScheduledFuture started...");

    while(true){
      if (count.get() > 5){
        System.out.println(Thread.currentThread().getName() + ": Cancelling scheduled task.");
        scheduledFuture.cancel(true);
        break;
      }
    }
    System.out.println("Ending test scheduler");
  }
}

actually the reason is that the multi thread has used the differect cpu core,so the same variable keep different value in the different cpu cache,you could just make the count to volatile to solve the problem.You could see the post http://tutorials.jenkov.com/java-concurrency/volatile.html if you are interesting about the volatile.The code is that实际上原因是多线程使用了不同的cpu核心,所以同一个变量在不同的cpu缓存中保持不同的值,你可以把count设置为volatile来解决这个问题。你可以看到帖子http:// tutorials.jenkov.com/java-concurrency/volatile.html如果您对 volatile 感兴趣。代码是

package com.test;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

/**
 *
 */
public class TestList {

    public static class TestScheduler {
        private static ScheduledExecutorService ses;
        private static volatile int count;

        public TestScheduler() {
            ses = Executors.newScheduledThreadPool(2);
            count = 0;
        }

        public void startScheduler() throws InterruptedException {
            System.out.println("startScheduler() thread: " + Thread.currentThread().getName());

            Runnable testTask = () -> {
                System.out.println(Thread.currentThread().getName() + ": count " + count++);
            };

            System.out.println("Starting test scheduler for 10s");
            ScheduledFuture<?> scheduledFuture = ses.scheduleWithFixedDelay(testTask, 5, 1, TimeUnit.SECONDS);
            System.out.println("ScheduledFuture started...");

            while (true) {
                // if any of the 2 lines below are uncommented, it works as I'd expect it to...
                // Thread.sleep(1000);
                // System.out.println(Thread.currentThread().getName() + ": count " + count);
                if (count > 5) {

                    System.out.println(Thread.currentThread().getName() + ": Cancelling scheduled task.");
                    scheduledFuture.cancel(true);
                    break;
                }
            }
            System.out.println("Ending test scheduler");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestScheduler test = new TestScheduler();
        test.startScheduler();
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM