java 使用mouseClicked()函数处理时线程出错

ha5z0ras  于 2023-05-27  发布在  Java
关注(0)|答案(1)|浏览(96)

在我的Processing应用程序中,我监听鼠标点击,然后在按钮类中处理它们。然后button类通过调用setScreenIndex设置正确的内容。该函数检测这是否是第一次加载屏幕,然后设置它(在示例化时不设置,因此如果用户不需要不必要的屏幕,则不加载它们)。设置是通过调用设置函数的线程完成的。然而,当鼠标忙碌时再次单击鼠标时,此线程似乎会中断。这会导致加载屏幕无限期地显示(线程仍然注册为活动,即使它不再执行任何操作),或者加载屏幕完全冻结。我相信这是一个线程问题,有些东西交互奇怪,但我迷路了,已经花了一个星期在这个问题上。相关代码如下:

final class Main
{
  public synchronized void update()
  {
    try
    {
      if (threadToWaitFor != null)
      {
        if (!threadToWaitFor.isAlive())
        {
          threadToWaitFor = null;
          setScreenIndex(nextScreenIndex);
        }
      }
      currentScreen.update();
    }
    catch (Exception e)
    {
      logger.println("ERROR: Main Update: " + e.getMessage());
      logger.println("Stack Trace: ");
      e.printStackTrace(logger);
      logger.flush();
      exit();
    }
  }
  public synchronized void setScreenIndex(int screenIndex)
  {
    this.screenIndex = screenIndex;
    currentScreen = screens.get(this.screenIndex);
    if (!currentScreen.getSetup())
    {
      SetupScreenThread thread = new SetupScreenThread(currentScreen);
      thread.start();
      waitForThread(thread, screenIndex);
    }
  }
  public synchronized void waitForThread(Thread thread, int newScreenIndex)
  {
    this.threadToWaitFor = thread;
    this.nextScreenIndex = newScreenIndex;
    this.currentScreen = loadScreen;
  }
}

我试过使用synchronised和volatile关键字检查按钮没有被调用两次,并且没有同时调用相同的函数,但这没有帮助。如果您没有多次单击,则一切正常,并且行为/加载正确。我试过在主类中实现一个锁,这样如果标志设置为忙碌,单击甚至不会到达主类,但这也不起作用。

fnx2tebb

fnx2tebb1#

我认为你解决问题的方法是错误的。
您正在尝试实现视图的延迟加载,这是一个好主意。但试图自己实现这一点并不是一个好主意。
您应该使用已经存在的允许异步计算的类。未来API是您的盟友。

public Map<String, Future<View>> views = initViews();

    public Future<View> currentView;

    public static Map<String, Future<View>> initViews() {
        Map<String, Future<View>> screens = new HashMap<>();
        screens.put("login", null);
        screens.put("home", null);

        return screens;
    }

    public synchronized void update() throws InterruptedException {
        ...
        if (currentView.isDone()) {
            try {
                View view = currentView.get();
                // do something with your view
            } catch (ExecutionException e) {
                // Exception was raised and not caught in your async method call
                throw new RuntimeException(e);
            }
        }
        ...
    }

    public synchronized void setScreenIndex(String viewName) {
        if (views.get(viewName) == null) {
            CompletableFuture<View> future = new CompletableFuture<>(() -> {
                switch (viewName) {
                    case "login":
                        return new LoginView();
                    case "home":
                        return new HomeView();
                    default:
                        throw new RuntimeException("Unknown view: " + viewName);
                }
            });
            views.put(viewName, future);
            future.whenComplete((view, throwable) -> {
                        if (throwable != null) {
                            throw new RuntimeException(throwable);
                        }
                        // Update current view
                        currentView = views.get(viewName);
                    }
            );
        } else
            currentView = views.get(viewName);
    }

这个代码并不意味着是完美的。只是为了给予您了解如何将Future API用于您的用例。

相关问题