Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions modules/javafx.graphics/src/main/java/javafx/concurrent/Task.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -25,6 +25,14 @@

package javafx.concurrent;

import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_CANCELLED;
import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_FAILED;
import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_RUNNING;
import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_SCHEDULED;
import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_SUCCEEDED;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicReference;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
Expand All @@ -43,14 +51,6 @@
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.event.EventType;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicReference;
import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_CANCELLED;
import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_FAILED;
import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_RUNNING;
import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_SCHEDULED;
import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_SUCCEEDED;

/**
* <p>
Expand Down Expand Up @@ -998,7 +998,8 @@ protected void failed() { }
return cancel(true);
}

@Override public boolean cancel(boolean mayInterruptIfRunning) {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
// Delegate to the super implementation to actually attempt to cancel this thing
// Assert the modifyThread permission
boolean flag = super.cancel(mayInterruptIfRunning);
Expand All @@ -1014,12 +1015,30 @@ protected void failed() { }
// state flag will not be readable immediately after this call. However,
// that would be the case anyway since these properties are not thread-safe.
if (isFxApplicationThread()) {
switch (getState()) {
case FAILED:
case SUCCEEDED:
Comment on lines +1018 to +1020
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoiding transitioning from a one of the completion states to canceled is a good thing. My question, though is: how did we get here? Is this masking some other problem?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the variations in the test timing uncovered this issue. I don't think it's a problem with the execution of the task, but rather with the reporting of its final state.

// a finished or failed task retains its state
return false;
}

setState(Worker.State.CANCELLED);
} else {
runLater(() -> setState(Worker.State.CANCELLED));
runLater(() -> {
// the state must be accessed only in the fx application thread
switch (getState()) {
case FAILED:
case SUCCEEDED:
// a finished or failed task retains its state
break;
default:
setState(Worker.State.CANCELLED);
break;
}
});
return flag;
}
}
// return the flag
return flag;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -25,9 +25,13 @@

package test.javafx.concurrent;

import test.javafx.concurrent.mocks.MythicalEvent;
import test.javafx.concurrent.mocks.SimpleTask;
import javafx.event.EventHandler;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
Expand All @@ -40,17 +44,13 @@
import javafx.concurrent.TaskShim;
import javafx.concurrent.Worker;
import javafx.concurrent.WorkerStateEvent;

import javafx.event.EventHandler;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import test.javafx.concurrent.mocks.MythicalEvent;
import test.javafx.concurrent.mocks.SimpleTask;

/**
* Tests various rules regarding the lifecycle of a Service.
Expand Down Expand Up @@ -1278,6 +1278,7 @@ public void removed_onSucceededFilterNotCalled() {
task.complete();
}

@RepeatedTest(50)
@Test
public void cancelCalledFromOnSucceeded() {
final AtomicInteger cancelNotificationCount = new AtomicInteger();
Expand Down Expand Up @@ -1422,6 +1423,7 @@ public void cancelCalledFromOnCancelled() {
assertEquals(1, cancelNotificationCount.get());
}

@RepeatedTest(50)
@Test
public void cancelCalledFromOnFailed() {
final AtomicInteger cancelNotificationCount = new AtomicInteger();
Expand Down