【问题标题】:Using Java stream forEach() in ScheduledExecutorService freezes在 ScheduledExecutorService 中使用 Java 流 forEach() 冻结
【发布时间】:2021-06-30 03:29:24
【问题描述】:

一般的想法是让 Runnable 在后台每 10 秒运行一次,以检查一些数据,并在需要时对对象进行更改。 ScheduledExecutorService 在方法 main() 中被实例化,并且任务被调度。 Runnable 任务实例化 Crawler 对象并开始爬取。大多数情况下,它成功运行了几次,但是当应用程序正在运行并且数据更改时,爬虫的方法之一被触发但永远不会结束。代码中没有循环。我试图调试也没有成功。也许您将能够发现问题所在。

主要:

public class Main {

    public static void main(String[] args) {

        DataStock dataStock = DataStock.getInstance();
        ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
        ses.scheduleAtFixedRate(new EveryFiveSeconds(), 5, 5, TimeUnit.SECONDS);
        // below the task which fails after couple of runs
        ses.scheduleAtFixedRate(new EveryTenSeconds(), 1 , 10, TimeUnit.SECONDS);
        dataStock.init();

        Menu currentScreen = new UserMenu();
        while(currentScreen != null) {
            currentScreen = currentScreen.display();
        }

    }
}

EveryTenSeconds Runnable:

public class EveryTenSeconds implements Runnable {
    @Override
    public void run() {
        Crawler crawler = new Crawler();
        crawler.crawl();
    }
}

爬虫:

public class Crawler {

    private final DataStock dataStock;

    public Crawler() {
        this.dataStock = DataStock.getInstance();
    }

    public void crawl() {
        checkOutRentables(dataStock.getCarServicesWithOwners().keySet());
        checkFinancialBook(dataStock.getPaymentsBook(), dataStock.getCurrentDate());
    }

    private void checkOutRentables(Set<CarService> carServices) {
        System.out.println("Start check...");
        carServices.stream()
                .flatMap(service -> service.getWarehousesSet().stream())
                .filter(rentable -> !rentable.isAvailableForRent())
                .forEach(RentableArea::refreshCurrentState);
        System.out.println("Checking finished");
    }

    private void checkFinancialBook(Set<BookEntry> bookEntries, LocalDate currentDate) {
        System.out.println("Start second check...");
        bookEntries.stream()
                .filter(bookEntry -> currentDate.isAfter(bookEntry.getPaymentDeadline()) && !bookEntry.isPaid() && !bookEntry.isNotified())
                .forEach(BookEntry::notifyDebtor);
        System.out.println("Finished second check..."); //this line never shows in one of runs and the task is never repeated again...

    }
}

图书入口

public class BookEntry {
    private final UUID rentableId = UUID.randomUUID();
    private final UUID personId;
    private final UUID id;
    private final BigDecimal amountDue;
    private final LocalDate paymentDeadline;
    private boolean paid = false;
    private boolean notified = false;

    public BookEntry(UUID personId, UUID id, BigDecimal amountDue, LocalDate paymentDeadline) {
        this.personId = personId;
        this.id = id;
        this.amountDue = amountDue;
        this.paymentDeadline = paymentDeadline;
    }

    public UUID getRentableId() {
        return rentableId;
    }

    public UUID getPersonId() {
        return personId;
    }

    public UUID getId() {
        return id;
    }

    public BigDecimal getAmountDue() {
        return amountDue;
    }

    public LocalDate getPaymentDeadline() {
        return paymentDeadline;
    }

    public boolean isPaid() {
        return paid;
    }

    public boolean isNotified() {
        return notified;
    }

    public void settlePayment() {
        if(!paid) {
            paid = true;
        }
        else {
            throw new IllegalStateException("This is already paid man!");
        }
    }

    public void notifyDebtor() {
        if(!notified) {
            notified = true;
            DataStock dataStock = DataStock.getInstance();
            Person debtor = dataStock.getPeople().stream()
                    .filter(person -> person.getId().equals(personId))
                    .findFirst()
                    .orElseThrow();
            debtor.alert(new TenantAlert(personId, rentableId, dataStock.getCurrentDate(), amountDue));
        }
    }
}

【问题讨论】:

  • 有趣。如果你要分享一个 repo,我会尝试调试它。
  • @BuildSlayer 这里是 repo:link 如果你能帮我解决这个问题,我将不胜感激。

标签: java foreach java-stream executorservice


【解决方案1】:

似乎答案很简单 - 每当 ScheduledExecutorService 中安排的任务抛出异常时,该任务就会停止并且不再重复。也不会明显抛出异常。避免这种情况的最简单方法是在 run() 中使用 try-catch 块,这是 Runnable 的方法。请看这篇帖子:ScheduledExecutorService handling exceptions

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多