我有一个启动几个线程的应用程序,最终一个线程可能需要退出整个应用程序,但是其他线程可能处于任务中间,因此我想让它们在退出之前继续其当前循环。
在下面的示例中,Thread2不知道何时Thread1试图退出,它只是强制所有操作立即完成。
如何让Thread2、3和4等在关闭之前完成它们的循环?
编辑::要解决重复的问题:与典型情况不同,父类不能负责伪造关闭,任何单独的线程都必须能够发起关闭请求。关闭。
Edit2 :我还留下了一个答案,最后是我做的是接受答案的实现。
class Scratch {
public static void main(String[] args) {
Thread Task1 = new Thread(new Task1());
Task1.start();
Thread Task2 = new Thread(new Task2());
Task2.start();
// ... more threads
}
public class Task1 implements Runnable {
public void run() {
while (true) {
// ...
System.exit(0);
// ...
}
}
}
public class Task2 implements Runnable {
public void run() {
while (true) {
// ...
// I need to know about System.exit(0) to exit my loop
// ...
}
}
}
}
答案 0 :(得分:3)
您可以使用所有线程将不断检查的volatile boolean
变量。如果一个线程将该变量的值设置为false
,则所有线程都将看到新值并离开while
循环。
说明:volatile
变量中的读/写操作是原子的。除此之外,volatile变量的值不会被缓存,因此所有线程都看到相同的值。
class Scratch {
private static volatile boolean isRunning = true;
public static void main(String[] args) {
Thread Task1 = new Thread(new Task1());
Task1.start();
Thread Task2 = new Thread(new Task2());
Task2.start();
// ... more threads
}
public class Task1 implements Runnable {
public void run() {
while (isRunning) {
// ...
isRunning = false; // let's stop all threads
// ...
}
}
}
public class Task2 implements Runnable {
public void run() {
while (isRunning) {
// ...
// I need to know about System.exit(0) to exit my loop
// ...
}
}
}
}
答案 1 :(得分:1)
您自己创建线程被认为是“不良做法”,您应该考虑使用ExecutorService。同步应该通过中断线程来完成。
class Scratch {
private final ExecutorService executorService;
public Scratch(ExecutorService es) {
this.executorService = es;
}
/** Convience constructor */
public Scratch() {this(Executors.newCachedThreadPool());}
public class Task1 implements Callable<Void> {
public Void call() throws Exception {
while(true) {
...
executorService.shutdownNow(); // interrupt all running threads
// (including Task1) started by
// given executor service
if (Thread.interrupted())
throw new InterruptedException();
}
return null;
}
}
public class Task2 implements Callable<Void> {
public Void call() throws Exception {
while(true) {
// check if the thread was interrupted, if so throw Exception
if (Thread.interrupted())
throw new InterruptedException();
}
return null;
}
}
public static void main(String ... args) {
Scratch s = new Scratch();
s.executorService.submit(new Task1());
s.executorService.submit(new Task2());
}
}
答案 2 :(得分:1)
除了通过使用 volatile布尔变量实现的方法(非常有用)之外,您还可以考虑使用 listeners 。它们通常在整个Android API中都使用。
首先,创建定义侦听器的接口。这是一个示例:
public interface TaskListener {
public void onFinish();
}
现在,在要通知您任务完成的类上实现此接口。看下面:
public class Task2 implements Runnable, TaskListener {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
//...
}
}
public void onFinish() {
//perform your exit operations here.
Thread.currentThread().interrupt();
}
}
现在,准备您的主要任务课程,以接收侦听器。看看:
public class Task1 implements Runnable {
private ArrayList<TaskListener> listeners = new ArrayList<>();
public void run() {
while (true) {
// ...
this.finish();
// ...
}
}
public void addListener (TaskListener listener) {
this.listeners.add(listener);
}
private void finish() {
for(TaskListener listener: this.listeners) {
listener.onFinish();
}
}
}
在完成所有设置后,现在很容易听完任务的完成情况。看下面:
public static void main(String[] args) {
Thread task1 = new Thread(new Task1());
Thread task2 = new Thread(new Task2());
task1.addListener(task2);
task1.start();
task2.start();
}
完成!现在,每次调用task1.finish()
时,它的所有侦听器(在此示例中仅为task2
)都被通知(它们的onFinish
方法被调用)。
注意:如果您不想在所有任务中实施TaskListener
。这是使用 lambda表达式的示例:
public static void main(String[] args) {
Thread task1 = new Thread(new Task1());
Thread task2 = new Thread(new Task2());
task1.addListener(() -> {
//this entire block will be called when task1 finishes
task2.interrupt();
});
task1.start();
task2.start();
}
注意2::我在手机上写下了这个答案。尽管我多次修改了代码,看起来还可以,但是直到我回到家,我才能对其进行测试。
答案 3 :(得分:0)
您不能轻易做到这一点。
首先System.exit(0)
退出JVM,并且它不关心线程。
您需要做什么:
当然:在现实世界中,您的应用程序中可能有很多线程运行着您甚至都不知道的线程(例如,当您在某处使用someCollection.parallelStream()
时:一个JVM范围内的线程池,其中的线程不在您的控制范围之内。
某些中间立场可能是“线程管理器”组件。不想被杀死的线程必须向该管理器注册。
但是仍然:即使这样很难。例如,当某些线程陷入僵局时会发生什么?还是等待JVM“外部”发生某些事情?要弄清线程是否还在真正地进展中,还需要花费大量的精力。
答案 4 :(得分:0)
按照@HugoTeixeira的建议,我最终使用了易失性和原子整数来跟踪线程。我还制作了一个控制线程来定期检查这些值并确定是否该退出。
class Scratch {
public static volatile boolean isRunning = true;
public static AtomicInteger threadCount = new AtomicInteger();
public static void main(String[] args) {
Thread controlThread = new Thread(new ControlThread());
controlThread.start();
Thread Task1 = new Thread(new Task1());
Task1.start();
if(Task1.isAlive()) { threadCount.incrementAndGet(); }
Thread Task2 = new Thread(new Task2());
Task2.start();
if(Task2.isAlive()) { threadCount.incrementAndGet(); }
// ... more threads
}
}
任务线程:
public class Task1 implements Runnable {
public void run() {
while (isRunning) {
// ...
isRunning = false; // let's stop all threads
// ...
}
}
}
控制线程:
import static Scratch.isRunning;
import static Scratch.threadCount;
public class ControlThread implements Runnable {
public void run() {
while(true) {
try {
// Check if we have stopped running the app AND all threads have finished up.
if(!isRunning && threadCount.get() == 0) {
// Safely close the app
System.exit(0);
}
Thread.sleep(5000);
} catch (InterruptedException e) {
// Ignore exceptions
}
}
}
}
答案 5 :(得分:0)
如果打算等待所有Thread
完成执行。考虑使用ExecutorService
和Future
。下面的草图代表了实现它的一般想法。
final ExecutorService pool = Executors.newCachedThreadPool();
Future<?> task1 = pool.submit(() -> {
//do loop task1
});
Future<?> task2 = pool.submit(() -> {
//do loop task2
});
while(!task1.isDone() && !task2.isDone()){
//waits to complete
}
所有任务完成后,使用pool.shutdown()
关闭执行程序。然而,这只是简单的例子。有关更多详细信息,请参见ExecutorService
javadoc。
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html