我有一堆线程,有些随意产生。当它们相互竞争时,只有最后生成的那个才是相关的。其他线程可以被丢弃或停止。但是我不确定如何做到这一点,所以我实现了一个非常基本的计数器,检查线程是否是最近派生的线程。
编辑:我希望能够杀死那些花费太长时间的线程(因为它们不再需要);可能不是来自线程本身,因为它们正忙着做其他事情。
这段代码似乎可以工作。但它感觉并不健壮。谁能给我点提示,告诉我做这件事的正确方法?
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
replit.com中的代码
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!
可以设置出生时间,而不是依赖索引。如果有一个较年轻的线程(出生较晚),线程应该终止它的执行。
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 :-(nt" + thisThread + "nt" + latestThread);
die = true;
} else if (thisThread == latestThread) {
System.out.println(
index + ": Yes! This is the latest thread!nt" + thisThread + "nt" + 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!