Потоки. В журнале не отображается "КОНЕЦ" - PullRequest
0 голосов
/ 26 мая 2020

У меня 2 класса: Первый класс Я вызываю Constructor в LogScheduler - это Singleton, конструктор создает новый поток и запускает его. Основной поток переходит в спящий режим 5 se c, затем я устанавливаю логическую переменную false, чтобы остановить l oop:

public class Launch {
    public static void main(String[] args) throws InterruptedException {
        LogScheduler log = LogScheduler.getInstance();
        Thread.sleep(5000);
        log.setActive(false);

        List<String> logs = log.getLogs();
        logs.add("ABBA");

        log.showLogs();
    }
}

Второй класс :

public class LogScheduler {

    public static final LogScheduler INSTANCE = new LogScheduler();

    private final List<String> logs = new ArrayList<>();

    private final Thread worker;

    private boolean active = true;

    private int i = 0;

    private LogScheduler() {
        addLog("Launch");
        worker = new Thread(this::log);
        worker.setName(getClass().getName());
        worker.start();
    }

    private void log() {
        addLog("Start");
        while (active) {
            synchronized (worker) {
                try {
                    System.out.println(Thread.currentThread()
                            .getName() + " - " + i++);
                    worker.wait(1000);
                } catch (InterruptedException e) {
                    System.out.println(e.getMessage());
                }
            }
        }
        addLog("End");
    }

    public void addLog(String value) {
            logs.add(value);
    }

    public void showLogs() {
        logs.forEach(System.out::println);
    }

    public List<String> getLogs() {
        return logs;
    }

    public void setActive(boolean active) {
        this.active = active;
    }

    public static LogScheduler getInstance() {
        return INSTANCE;
    }

    public Thread getWorker() {
        return worker;
    }
}

Console Out :

job.LogScheduler - 0
job.LogScheduler - 1
job.LogScheduler - 2
job.LogScheduler - 3
job.LogScheduler - 4
Launch
Start
ABBA

'End' - слово в методе log () не отображается в консоли. Дайте несколько советов, чтобы исправить это, пожалуйста. Я пробую синхронизировать переменную журналов и метод addLog, это не помогает.

Ответы [ 2 ]

0 голосов
/ 26 мая 2020

При звонке на log.getLogs() «Конец» еще не написано. Чтобы проиллюстрировать, что вы можете попробовать эту основную функцию, в которой я добавляю еще один сон перед log.getLogs(), что даст достаточно времени, чтобы написать «Конец»:

public class Launch {
    public static void main(String[] args) throws InterruptedException {
        LogScheduler log = LogScheduler.getInstance();
        Thread.sleep(5000);
        log.setActive(false);

        //new sleep
        Thread.sleep(5000);
        List<String> logs = log.getLogs();

        logs.add("ABBA");

        log.showLogs();
    }
}
0 голосов
/ 26 мая 2020

Когда вы устанавливаете active в false, вы не даете регистратору достаточно времени, чтобы увидеть это изменение. Он ждет в worker.wait, когда вы устанавливаете active в false, и переходите к завершению sh программы.

У вас должен быть notify рабочий, когда вы устанавливаете active:

public void setActive(boolean active) {
    synchronized(worker) {
        this.active = active;
        worker.notify()
    }
}

Итак, когда вы меняете активный, worker.wait уведомляется.

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

У вас тоже есть гонка данных. Когда вы добавляете / читаете журналы, вы не синхронизируете доступ к общему списку журналов. Либо синхронизируйте доступ к нему, либо используйте синхронизированную коллекцию для хранения журналов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...