Хостинг серверов Minecraft playvds.com
  1. Вы находитесь в русском сообществе Bukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на русский язык плагины наших собратьев из других стран.
    Скрыть объявление

[Решено] Странный while в отдельном потоке

Тема в разделе "Разработка плагинов для новичков", создана пользователем sashabelii, 25 окт 2014.

  1. Автор темы
    sashabelii

    sashabelii Старожил Пользователь

    Баллы:
    123
    Имя в Minecraft:
    sashabelii
    Доброго.

    Есть отдельный поток, который хранит в себе мир, ждет пока тики побегут после массивной операции в основном потоке, потом отсчитывает некоторое их количество и продолжает работу:
    Код:
        @Override
        public void run() {
        ...
                long timeFrom = world.getFullTime();
                while(world.getFullTime() < timeFrom + pushTimeout) {
                    System.out.println();
                }
        ...
    }
    Я до конца не понимаю, что на это влияет, но цикл зависает/зацикливается, если не вызывать внутри него методы System.out.println();/поток.sleep(N);(возможно еще какие-то подойдут).
    Почему так?
     
  2. Хостинг MineCraft
    <
  3. ptnk

    ptnk Старожил Пользователь

    Баллы:
    173
    1) Шедуллеры - это не потоки, это просто задания, который выполняются.
    2) Есть вероятность того, что ты делаешь deadlock тем, что работаешь с миром не из основного потока. Нужно ознакомиться с конкуренцией в java.
     
  4. serega6531

    serega6531 Старожил Девелопер Пользователь

    Баллы:
    173
    Skype:
    shkurovs
    Весь этот код выполняется во время одного тика. Условие в цикле становится ложным только при отрицательном pushTimeout.
     
  5. Автор темы
    sashabelii

    sashabelii Старожил Пользователь

    Баллы:
    123
    Имя в Minecraft:
    sashabelii
    Извиняюсь, не ясно выразился. Будет понятнее, если я покажу весь код:
    // Все это дело работает в отдельном потоке, это не запланированная задача.
    Код:
    public class ChunkCalculator extends Thread {
    ...
        @Override
        public void run() {
            EditSession editSession = WorldCleaner.worldEdit.getWorldEdit().getEditSessionFactory().getEditSession(BukkitUtil.getLocalWorld(world), 0);
            ChunkStore chunkStore = null;
            try {
                chunkStore = WorldCleaner.worldEdit.getLocalConfiguration().snapshotRepo.getSnapshot(world.getName() + File.separator + Config.getSnapshotName(world.getName())).getChunkStore();
            } catch (IOException | InvalidSnapshotException | DataException e) {
                e.printStackTrace();
            }
    
            calculateChunksInRadius(radiusInChunks);
    
            WorldCleaner.log.info("Calculating chunks for world: "+ world.getName() + " is done. To regenerate: " + chunks.size() + " chunks. ");
    
            if (isFromSnapshot) {
                WorldCleaner.log.info("Starts world restoring from snapshot: " + Config.getSnapshotName(world.getName()));
            } else {
                WorldCleaner.log.info("Starts world regenerating...");
            }
    
            while(!chunks.isEmpty() && isRunning) {  // Пушим
    
                Queue<Vector2D> currentChunks = chunks.getLast();
                if (isFromSnapshot) {
                    worker = new ChunkRestorer(world, currentChunks, editSession, chunkStore);
                } else {
                    worker = new ChunkRegenerator(world, currentChunks);
                }
                Bukkit.getServer().getScheduler().runTask(WorldCleaner.plugin, worker);
                chunks.removeLast();
    
                // Ждем тики и соответсвенно завершение работы с пушем чанков(тики в этот момент стоят)
                long timeFrom = world.getFullTime();
                while(world.getFullTime() < timeFrom + pushTimeout) {
                    System.out.println();
                }
                checkMemoryLevel();
            }
            WorldCleaner.regeneratorsMng.continueRegenerating();
        }
    ...
    
    Работаю из основного. Я почти уверен, что getFullTime потоко-безопасный метод.

    Главный вопрос: Что такого делает System.out.println();, что цикл работает как нужно?
     
  6. serega6531

    serega6531 Старожил Девелопер Пользователь

    Баллы:
    173
    Skype:
    shkurovs
    Тормозит цикл?
     
  7. Автор темы
    sashabelii

    sashabelii Старожил Пользователь

    Баллы:
    123
    Имя в Minecraft:
    sashabelii
    Каким образом вывод строки может остановить цикл? :)
    С ним цикл ждет заданное количество тиков и продолжает работу как оно и нужно.
     
  8. serega6531

    serega6531 Старожил Девелопер Пользователь

    Баллы:
    173
    Skype:
    shkurovs
    Вывод строки тоже время занимает.
     
  9. Автор темы
    sashabelii

    sashabelii Старожил Пользователь

    Баллы:
    123
    Имя в Minecraft:
    sashabelii
    Т.е. while не может до какого-то момента делать "ничего"?[DOUBLEPOST=1414244000,1414242924][/DOUBLEPOST]Загуглил, понял. while судя по всему занимает все процессорное время, или что-то в этом духе. Все свелось к ожиданию по времени во имя пропуска постоянных пустых циклов, которые делают "ничего".
    Код:
                long timeFrom = world.getFullTime();
                while(world.getFullTime() < timeFrom + pushTimeout) {
                    try {
                        sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
    Такие дела.
     
  10. Shevchik

    Shevchik Старожил Пользователь

    Баллы:
    173
    Имя в Minecraft:
    _Shevchik_
    Когда-то накатал такое чтобы шедулить таск и ожидать оконачания его выполнения.
    https://github.com/Shevchik/AutoSaveWorld/blob/devel/src/autosaveworld/utils/SchedulerUtils.java#L43
     
  11. Автор темы
    sashabelii

    sashabelii Старожил Пользователь

    Баллы:
    123
    Имя в Minecraft:
    sashabelii

Поделиться этой страницей