Тупик, возникающий при использовании java.nio.file.Paths & jsfml loadFromFile

Я пытался отладить проблему с загрузкой шрифта из файла (файл .ttf) с помощью импорта java.nio.file.Paths, используя комбинацию Paths.get () и loadFromFile (), но не могу найти решения.

Вот код проблемы:

      import java.io.IOException;
import java.nio.file.Paths;

    public final Font FONT_UI_BAR = new Font();
    public final Font FONT_FREESANS = new Font();

    try {
                System.out.println("We get here, before loading");
                FONT_UI_BAR.loadFromFile(Paths.get("Game/resources/UI/Font.ttf"));
                System.out.println("I've loaded the first font");
                FONT_FREESANS.loadFromFile(Paths.get("Game/resources/fonts/freesans/freesans.ttf"));
            } catch (IOException e2) {
                System.out.println("[ERROR] Could not load font");
                e.printStackTrace();
            }

Программа переходит к первому оператору печати, но не достигает второго.

Я сделал дамп потока и обнаружил, что в самом коде есть тупик:

      "main@1" prio=5 tid=0x1 nid=NA waiting
  java.lang.Thread.State: WAITING
      at jdk.internal.misc.Unsafe.park(Unsafe.java:-1)
      at java.util.concurrent.locks.LockSupport.park(LockSupport.java:194)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:885)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1039)
      at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1345)
      at java.util.concurrent.Semaphore.acquire(Semaphore.java:318)
      at org.jsfml.internal.SFMLErrorCapture.start(Unknown Source:-1)
      at org.jsfml.graphics.Font.loadFromFile(Unknown Source:-1)
      at assets.FontCatalogue.<init>(FontCatalogue.java:32)
      at assets.FontCatalogue.get(FontCatalogue.java:15)
      at screens.HomeScreen.<init>(HomeScreen.java:51)
      at controllers.Game.<init>(Game.java:74)
      at Main.main(Main.java:16)

Я не совсем уверен, что делать дальше. Моя программа не будет работать так, как я хочу, без загрузки этих шрифтов. Я попытался загрузить другие шрифты, но проблема не устранена.

Как ни странно, проблема не возникала при загрузке других файлов в прошлом, таких как этот код:

      TEMP_BG_01.loadFromFile(Paths.get("Game/resources/placeholder/full-moon_bg.png"));

Это началось только после того, как я начал пытаться загрузить эти шрифты.

В идеале я хотел бы найти решение, которое по-прежнему позволяет мне использовать этот пакет, потому что в противном случае мне нужно переписать изрядное количество кода. Не самая большая сделка, но предложение просто использовать другой пакет должно быть последним средством.

Любые идеи приветствуются.

РЕДАКТИРОВАТЬ: интересно отметить, что эта проблема НЕ возникает на машине с Windows, только на моем ubuntu-linux. Остальная часть моей команды по Windows не имеет проблем. Очевидно, одно из решений - пойти и использовать Windows вместо этого, но кто хочет это сделать:p

РЕДАКТИРОВАТЬ № 2: Оказывается, теперь я получаю эту ошибку даже при загрузке из класса текстуры в JSFML. У меня есть ощущение, что я обновил свою JVM, когда недавно обновил свой ubuntu, и это внезапно привело к проблемам. Я не могу сказать наверняка, потому что не помню, чтобы обновлялся совсем недавно, но похоже, что на 21.02.2021 загрузка из файла с JSFML вызывает тупик:/

1 ответ

Решение

Первое, что вам нужно сделать, если вы хотите продолжить использование JSFML, - это определить начальный сбой, который оставляет вас в состоянии тупика.

Код в SFMLErrorCaptureкласс не является надежным. Должен SFMLErrorCapture.start()сбой в любом случае, он оставит семафор заблокированным. Я подозреваю, что это первоначальный сбой, который сломает ваше приложение и оставит его в тупике.

Я бы рекомендовал добавить в класс ведение журнала, например:

      public static void start() {
    try {
        semaphore.acquire();
        capturing = true;

        nativeStart();
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    } catch (Throwable t) {
        t.printStackTrace();

        // lots of other logging, probably to a file in /tmp

        // rethrow so original program flow isn't changed
        throw t;
    }
}

Вы также можете добавить больше журналов, чтобы увидеть, есть ли у вас InterruptedExceptionс. Это еще один способ, которым семафор никогда не будет выпущен, но я не думаю, что простое обновление может вызвать такое изменение поведения.

И поскольку это также возможно для finish() потерпеть неудачу таким же образом (например, если nativeFinish() возвращается null, который, я думаю, также является вероятным режимом отказа ...):

      public static String finish() {
    try {
        final String str;
        if (capturing) {
            str = nativeFinish().trim();

            capturing = false;
            semaphore.release();
        } else {
            str = null;
        }

        return str;
    } catch (Throwable t) {
        t.printStackTrace();
        // lots of logging
        throw t;
    }
}

Вам может потребоваться добавить throws Throwable к обоим методам.

Это также может помочь:

      public static String finish() {
    try {
        final String str;
        if (capturing) {
            // chaining calls is BAD CODE!!!!
            // Say hello to NPE if you insist cramming
            // multiple calls in one line!!
            str = nativeFinish();
            if ( str != null ) {
                str = str.trim();
            }

            capturing = false;
            semaphore.release();
        } else {
            str = null;
        }

        return str;
    }
}

Ограничение подобных асинхронных действий одним за раз в корне нарушено. Если одновременно может произойти только одно действие, сложность кода, добавленная для асинхронного выполнения действий, будет хуже, чем потраченная впустую, потому что такой сложный код гораздо более подвержен ошибкам, а когда ошибки действительно возникают, эта сложность делает неисправимые сбои гораздо более вероятными.

Если вы можете делать только одно за раз, просто выполняйте действия последовательно с одним static synchronized метод или в одном synchronized блок на static final объект.

Другие вопросы по тегам