首页 > 解决方案 > 线程。不在日志中显示“END”

问题描述

我有 2 个类: 第一类我在 LogScheduler 中调用构造函数 - 是单例,构造函数创建新线程并启动它。主线程在 5 秒后进入睡眠状态,然后我将布尔变量设置为 false 以停止循环:

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;
    }
}

控制台输出

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

'End' - log() 方法中的单词不会显示在控制台中。 请给一些建议来解决它。我尝试同步日志变量和 addLog 方法,它没有帮助。

标签: javamultithreading

解决方案


当您设置active为 false 时,您没有给记录器足够的时间来查看该更改。它正在等待worker.wait您将 active 设置为 false,然后继续完成程序。

当您设置为活动时,您必须对notify工人:

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

因此,当您更改活动时,worker.wait会收到通知。

但是,即使这样,也有会打印最后一个日志的执行,也有不会打印最后一个日志的执行,因为您的程序可能会在工作人员有机会添加最后一个日志之前终止。您需要进一步同步以保证这一点,或者您可以在从 main 返回之前稍等片刻。

你也有数据竞赛。当您添加/读取日志时,您不会同步对共享日志列表的访问。要么同步访问它,要么使用同步的集合来存储日志。


推荐阅读