如何创建单任务 FILO 后台线程?

How do I make a single-task FILO background thread?

我有一堆随机生成的线程。当他们互相比赛时,只有最后产生的那个才是相关的。其他线程可以被丢弃或停止。但我不确定该怎么做,所以我实现了一个非常基本的计数器来检查线程是否是最新生成的线程。

编辑:我希望能够终止耗时过长的线程(因为它们不再需要);可能不是来自线程本身,因为它们正忙于做其他事情。

这段代码似乎有效。但是感觉不是很结实。有人可以给我一些正确方法的提示吗?

class Main {
    private static volatile int latestThread = 0;

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            spawnThread();
        }
    }

    private static void spawnThread() {
        latestThread++;
        int thisThread = latestThread;
        new Thread(() -> {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (latestThread == thisThread) {
                // only the latest "active" thread is relevant
                System.out.println("I am the latest thread! " + thisThread);
            }
        }).start();
    }
}

输出:

I am the latest thread! 10

code in replit.com

可以设置出生时间,而不是依赖于索引。如果有一个更年轻的线程(后来出生)线程应该终止它的执行。

public class Last {
    private static volatile long latestThread = 0L;

    /**
     * @param args
     */
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            spawnThread(System.nanoTime(), i);
        }
    }

    private static void spawnThread(long startTime, int index) {
        new Thread(() -> {
            latestThread = startTime;
            long thisThread = startTime;
            boolean die = false;
            try {
                while (!die) {
                    Thread.sleep(1);
                    if (thisThread < latestThread) {
                        System.out.println(
                                index + ": I am not the latest thread :-(\n\t" + thisThread + "\n\t" + latestThread);
                        die = true;
                    } else if (thisThread == latestThread) {
                        System.out.println(
                                index + ": Yes! This is the latest thread!\n\t" + thisThread + "\n\t" + latestThread);
                        Thread.sleep(1);
                        System.out.println("Bye!");
                        die = true;
                    }
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

结果:

0: I am not the latest thread :-(
    39667589567880
    39667602317461
2: Yes! This is the latest thread!
    39667602317461
    39667602317461
1: I am not the latest thread :-(
    39667602257160
    39667602317461
Bye!

我根据大家的评论做了一些研究(谢谢!)ThreadPoolExecutor 几乎 我需要的,但我想要一个总大小的池1(无队列)一旦新线程出现就会杀死活动线程,这在线程池中是不允许的,也不符合 ThreadPool 的用途。所以相反,我想出了一个对活动线程的引用,当一个新线程出现时,它会杀死旧线程,这似乎是我想要的:

import java.util.concurrent.atomic.AtomicInteger;

public class Interrupt {

    private static final AtomicInteger CURRENT_THREAD = new AtomicInteger(0);
    private static Thread activeThread = new Thread(() -> {});

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 4; i++) {
            spawnThread();
            Thread.sleep(3);
        }
    }

    private static void spawnThread() {
        if (activeThread.isAlive()) {
            activeThread.interrupt();
        }
        activeThread = new Thread(() -> {
            int thisThread = CURRENT_THREAD.incrementAndGet();
            System.out.println(thisThread + " working");
            try {
                Thread.sleep(1000);
                System.out.println(thisThread + " finished!");
            } catch (InterruptedException ignored) {}
        });
        activeThread.start();
    }
}

输出:

3 working
2 working
1 working
4 working
4 finished!

ThreadPoolExecutor 几乎就是我所需要的,特别是 DiscardOldestPolicy。您可以将队列大小设置为 1,这样一个线程是 运行 并且一个线程在队列中,队列中最早的线程被分流。干净!

但它完成了两个线程(不仅是最新的),这不是我想要的 100%。虽然可以说已经足够好了:

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class DiscardOldest {

    private static int threadCounter = 1;

    public static void main(String[] args) throws InterruptedException {
        int poolSize = 0;
        int maxPoolSize = 1;
        int queueSize = 1;
        long aliveTime = 1000;
        ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(queueSize);
        ThreadPoolExecutor executor = new ThreadPoolExecutor(poolSize, maxPoolSize, aliveTime, TimeUnit.MILLISECONDS, queue, new ThreadPoolExecutor.DiscardOldestPolicy());

        for (int i = 0; i < 4; i++) {
            spawnThread(executor);
        }
    }

    private static void spawnThread(ThreadPoolExecutor executor) {
      final int thisThread = threadCounter++;
      System.out.println(thisThread + " spawning");
        executor.execute(() -> {
            try { 
                Thread.sleep(100);
                System.out.println(thisThread + " finished!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    }
}

输出:

1 spawning
2 spawning
3 spawning
4 spawning
1 finished!
4 finished!