[英]How to stop scheduled task/thread outside of thread
我正在嘗試練習和了解有關多線程和調度任務的更多信息。
我編寫了一個測試程序,該程序模仿了我試圖在機器人中實現的調度程序,並且它的行為方式我並不真正理解。 基本上我創建了一個任務並安排它運行,我希望它在某些事件之后被取消(在這種情況下,當計數 > 5 時)。
即使計數超過 5,它似乎也無限期地運行,但是當我放入一行以使主線程休眠或從中打印時,它會按我的預期工作。
有人可以為什么會這樣嗎?
就好像沒有與主線程的交互,它永遠不會達到條件或只是忽略它,但是一旦我將一些東西放入主線程進行處理,它也會檢查條件。
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");
}
這是 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
...
並且沒有注釋 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
如果有任何資源可以解釋為什么會發生上述情況,並且可能有一個用於介紹多線程的資源,我將不勝感激。
此外,是否有一種理想的方法來處理相關線程之外的取消線程,比如有一個專門用於檢查/管理條件的方法?
它是由於訪問count
時的競爭條件而發生的。
2 個線程同時訪問這個變量,沒有任何鎖。
您可以使用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");
}
}
實際上原因是多線程使用了不同的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.