Тупик, возникающий при использовании 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
объект.