简体   繁体   English

Function 在 notifyAll() 后继续,但在 function 返回后线程终止

[英]Function continues after notifyAll(), but Thread terminates after function returns

Basically, Thread A wait()'s on a lock object, then Thread B notifyAll()'s.基本上,线程 A wait() 锁定 object,然后是线程 B notifyAll()。 The function on thread A finishes, but doesn't return for normal operation.线程 A 上的 function 完成,但不会返回正常操作。

It may be of note that I am using JavaFX.值得注意的是,我使用的是 JavaFX。 In order to keep my FX Thread separate from my work Threads, I make a new Thread in order to prevent issues when I lock it and such.为了使我的 FX 线程与我的工作线程分开,我创建了一个新线程以防止在我锁定它时出现问题等。

Here's my code (pared down to the functions in question):这是我的代码(简化为有问题的函数):

public class ShortcutManager {

    private static final StringProperty STATE = new SimpleStringProperty("Create Shortcut");

    public static void create() {
        Thread creationThread = new Thread(() -> {
            // Do some work (sends logs to the logger)
            String result = prompt();
            if (result != null) {
                // Do more work (sends logs to the logger)
            } else {
                // Do other work (sends logs to the logger)
            }
        }
        creationThread.start();
    }

private static String prompt() {
    STATE.setValue("Waiting for user...");
    String result = popup.showAndWait();
    System.out.println("Result: \"" + result + "\"");
    return result;
}
public class CmlPopup implements Initializable {

    private boolean isClosed = false;

    public synchronized String showAndWait() {
        isClosed = false;
        Platform.runLater(() -> {
            stage.show();
        });
        while (!isClosed) {
            try {
                System.out.println("Waiting.");
                wait();
                System.out.println("Notified.");
            } catch (InterruptedException ex) {

            }
        }
        return getResult();
    }

    public synchronized void close() {
        stage.close();
        isClosed = true;
        System.out.println("Closing and notifying");
        notifyAll();
    }

}

Now - why am I locking it myself when the Stage has a showAndWait() function?现在 - 当舞台有 showAndWait() function 时,为什么我要自己锁定它? Because that wasn't working either, plus it ends up pausing the FX thread instead of the creation thread, since both show() and showAndWait() must occur on the FX thread.因为那也不起作用,而且它最终会暂停 FX 线程而不是创建线程,因为 show() 和 showAndWait() 都必须在 FX 线程上发生。

My output is as follows:我的output如下:

. . .

ShortcutManager State: Waiting for user...
Waiting.
Closing and notifying.
Notified.

And then nothing more.然后仅此而已。 No printing of the result;不打印结果; no other work is done by the thread.线程没有其他工作。 My FX thread and other work threads operate fine, but this one seems to just terminate even though there is still more to be done.我的 FX 线程和其他工作线程运行良好,但这个似乎只是终止,即使还有更多工作要做。

PS Before you criticize me, I'm using Loggers where I intend to retain them, and System.out when I intend to remove them. PS 在你批评我之前,我在打算保留它们的地方使用 Loggers,当我打算删除它们时使用 System.out。

First - thank you to those helpful folks that commented.首先-感谢那些评论的乐于助人的人。 Although your solutions did not work for me, they pointed me in the right direction.尽管您的解决方案对我不起作用,但它们为我指明了正确的方向。

Now, my solution: I simply wrapped the popup result, blocking, etc in a CompletableFuture.现在,我的解决方案:我只是将弹出结果、阻塞等包装在 CompletableFuture 中。

public class CmlPopup<R, D> implements Initializable {
    
    private final Object closeLock = new Object();
    private volatile boolean isClosed = false;

    ----

    public CompletableFuture<R> showAndGet() {
        Platform.runLater(() -> {
            stage.show();
        });
        return CompletableFuture.supplyAsync(() -> {
            synchronized (closeLock) {
                while (!isClosed) {
                    try {
                        closeLock.wait();
                    } catch (InterruptedException ex) {
                        
                    }
                }
                return contentManager.getResult();
            }
        }

    public void showThenRun(BiConsumer<? super R, ? super Throwable> action) {
        CompletableFuture.supplyAsync(() -> {
            synchronized (closeLock) {
                while (!isClosed) {
                    try {
                        closeLock.wait();
                    } catch (InterruptedException ex) {
                        
                    }
                }
                return contentManager.getResult();
            }
        }).whenComplete(action);
        Platform.runLater(() -> {
            stage.show();
        });
    }

    public void close() {
        stage.close();
        synchronized (closeLock) {
            isClosed = true;
            closeLock.notifyAll();
        }
    }

}
public class ShortcutManager {

    private static final CmlPopup<String, Integer> POPUP = new CmlPopup(...);

    ----

    private static void prompt(File userData) {
        POPUP.showThenRun((String result, Throwable ex) -> {
            System.out.println("Result: \"" + result+ "\"");
            ShortcutManager.identifyAndGridImages(result, userData);
        });
    }
    
    ----
    
}

This works perfectly reliably.这完全可靠。 For whatever reason, having a CompletableFuture for the object itself never runs the whenComplete function even the the future is supposedly "complete."无论出于何种原因,为 object 本身拥有 CompletableFuture 永远不会运行 whenComplete function,即使未来也被认为是“完整的”。

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

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