/*
* Copyright (c) 2010, 2018, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.concurrent;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import javafx.application.Platform;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.Event;
import javafx.event.EventDispatchChain;
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;
A fully observable implementation of a FutureTask
. Task
exposes additional state and observable properties useful for programming asynchronous tasks in JavaFX, as defined in the Worker
interface. An implementation of Task must override the call()
method. This method is invoked on the background thread. Any state which is used in this method must be safe to read and write from a background thread. For example, manipulating a live scene graph from this method is unsafe and will result in runtime exceptions.
Tasks are flexible and extremely useful for the encapsulation of "work". Because Service
is designed to execute a Task, any Tasks defined by the application or library code can easily be used with a Service. Likewise, since Task extends from FutureTask, it is very easy and natural to use a Task with the java concurrency Executor
API. Since a Task is Runnable, you can also call it directly (by invoking the FutureTask.run()
method) from another background thread. This allows for composition of work, or pass it to a new Thread constructed and executed manually. Finally, since you can manually create a new Thread, passing it a Runnable, it is possible to use the following idiom:
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
Note that this code sets the daemon flag of the Thread to true. If you
want a background thread to prevent the VM from exiting after the last
stage is closed, then you would want daemon to be false. However, if
you want the background threads to simply terminate after all the
stages are closed, then you must set daemon to true.
Although ExecutorService
defines several methods which take a Runnable, you should generally limit yourself to using the execute
method inherited from Executor
.
As with FutureTask, a Task is a one-shot class and cannot be reused. See Service
for a reusable Worker
.
Because the Task is designed for use with JavaFX GUI applications, it ensures that every change to its public properties, as well as change notifications for state, errors, and for event handlers, all occur on the main JavaFX application thread. Accessing these properties from a background thread (including the call()
method) will result in runtime exceptions being raised. The only exception to this, is when initially configuring a Task, which may safely be done from any thread. However, once the Task has been initialized and started, it may only thereafter be used from the FX thread (except for those methods clearly marked as being appropriate for the subclass to invoke from the background thread).
It is strongly encouraged that all Tasks be initialized with
immutable state upon which the Task will operate. This should be done by providing
a Task constructor which takes the parameters necessary for execution of the Task.
Immutable state makes it easy and safe to use from any thread and ensures
correctness in the presence of multiple threads.
In Java there is no reliable way to "kill" a thread in process. However,
when cancel
is called on a Task, it is important that
the Task stop processing. A "run-away" Task might continue processing
and updating the message, text, and progress properties even after the
Task has been cancelled! In Java, cancelling a Task is a cooperative
endeavor. The user of the Task will request that it be cancelled, and
the author of the Task must check whether is has been cancelled within
the body of the call
method. There are two ways this can
be done. First, the Task author may check the isCancelled method,
inherited from FutureTask
, to see whether the Task has
been cancelled. Second, if the Task implementation makes use of any
blocking calls (such as NIO InterruptibleChannels or Thread.sleep) and
the task is cancelled while in such a blocking call, an
InterruptedException is thrown. Task implementations which have blocking
calls should recognize that an interrupted thread may be the signal for
a cancelled task and should double check the isCancelled method to ensure
that the InterruptedException was thrown due to the cancellation of the
Task.
Examples
The following set of examples demonstrate some of the most common uses of
Tasks.
A Simple Loop
The first example is a simple loop that does nothing particularly useful,
but demonstrates the fundamental aspects of writing a Task correctly. This
example will simply loop and print to standard out on each loop iteration.
When it completes, it returns the number of times it iterated.
Task<Integer> task = new Task<Integer>() { @Override protected Integer call() throws Exception { int iterations; for (iterations = 0; iterations < 100000; iterations++) { if (isCancelled()) { break; } System.out.println("Iteration " + iterations); } return iterations; } };
First, we define what type of value is returned from this Task. In this
case, we want to return the number of times we iterated, so we will
specify the Task to be of type Integer by using generics. Then, within
the implementation of the call
method, we iterate from
0 to 100000. On each iteration, we check to see whether this Task has
been cancelled. If it has been, then we break out of the loop and return
the number of times we iterated. Otherwise a message is printed to
the console and the iteration count increased and we continue looping.
Checking for isCancelled() in the loop body is critical, otherwise the
developer may cancel the task, but the task will continue running
and updating both the progress and returning the incorrect result
from the end of the call
method. A correct implementation
of a Task will always check for cancellation.
A Simple Loop With Progress Notification
Similar to the previous example, except this time we will modify the
progress of the Task in each iteration. Note that we have a choice
to make in the case of cancellation. Do we want to set the progress back
to -1 (indeterminate) when the Task is cancelled, or do we want to leave
the progress where it was at? In this case, let's leave the progress alone
and only update the message on cancellation, though updating the
progress after cancellation is a perfectly valid choice.
Task<Integer> task = new Task<Integer>() { @Override protected Integer call() throws Exception { int iterations; for (iterations = 0; iterations < 10000000; iterations++) { if (isCancelled()) { updateMessage("Cancelled"); break; } updateMessage("Iteration " + iterations); updateProgress(iterations, 10000000); } return iterations; } };
As before, within the for loop we check whether the Task has been
cancelled. If it has been cancelled, we will update the Task's
message to indicate that it has been cancelled, and then break as
before. If the Task has not been cancelled, then we will update its
message to indicate the current iteration and then update the
progress to indicate the current progress.
A Simple Loop With Progress Notification And Blocking Calls
This example adds to the previous examples a blocking call. Because a
blocking call may thrown an InterruptedException, and because an
InterruptedException may occur as a result of the Task being cancelled,
we need to be sure to handle the InterruptedException and check on the
cancel state.
Task<Integer> task = new Task<Integer>() { @Override protected Integer call() throws Exception { int iterations; for (iterations = 0; iterations < 1000; iterations++) { if (isCancelled()) { updateMessage("Cancelled"); break; } updateMessage("Iteration " + iterations); updateProgress(iterations, 1000); // Now block the thread for a short time, but be sure // to check the interrupted exception for cancellation! try { Thread.sleep(100); } catch (InterruptedException interrupted) { if (isCancelled()) { updateMessage("Cancelled"); break; } } } return iterations; } };
Here we have added to the body of the loop a Thread.sleep
call. Since this is a blocking call, I have to handle the potential
InterruptedException. Within the catch block, I will check whether
the Task has been cancelled, and if so, update the message accordingly
and break out of the loop.
A Task Which Takes Parameters
Most Tasks require some parameters in order to do useful work. For
example, a DeleteRecordTask needs the object or primary key to delete
from the database. A ReadFileTask needs the URI of the file to be read.
Because Tasks operate on a background thread, care must be taken to
make sure the body of the call
method does not read or
modify any shared state. There are two techniques most useful for
doing this: using final variables, and passing variables to a Task
during construction.
When using a Task as an anonymous class, the most natural way to pass
parameters to the Task is by using final variables. In this example,
we pass to the Task the total number of times the Task should iterate.
final int totalIterations = 9000000; Task<Integer> task = new Task<Integer>() { @Override protected Integer call() throws Exception { int iterations; for (iterations = 0; iterations < totalIterations; iterations++) { if (isCancelled()) { updateMessage("Cancelled"); break; } updateMessage("Iteration " + iterations); updateProgress(iterations, totalIterations); } return iterations; } };
Since totalIterations
is final, the call
method can safely read it and refer to it from a background thread.
When writing Task libraries (as opposed to specific-use implementations),
we need to use a different technique. In this case, I will create an
IteratingTask which performs the same work as above. This time, since
the IteratingTask is defined in its own file, it will need to have
parameters passed to it in its constructor. These parameters are
assigned to final variables.
public class IteratingTask extends Task<Integer> { private final int totalIterations; public IteratingTask(int totalIterations) { this.totalIterations = totalIterations; } @Override protected Integer call() throws Exception { int iterations = 0; for (iterations = 0; iterations < totalIterations; iterations++) { if (isCancelled()) { updateMessage("Cancelled"); break; } updateMessage("Iteration " + iterations); updateProgress(iterations, totalIterations); } return iterations; } }
And then when used:
IteratingTask task = new IteratingTask(8000000);
In this way, parameters are passed to the IteratingTask in a safe
manner, and again, are final. Thus, the call
method can
safely read this state from a background thread.
WARNING: Do not pass mutable state to a Task and then operate on it
from a background thread. Doing so may introduce race conditions. In
particular, suppose you had a SaveCustomerTask which took a Customer
in its constructor. Although the SaveCustomerTask may have a final
reference to the Customer, if the Customer object is mutable, then it
is possible that both the SaveCustomerTask and some other application code
will be reading or modifying the state of the Customer from different
threads. Be very careful in such cases, that while a mutable object such
as this Customer is being used from a background thread, that it is
not being used also from another thread. In particular, if the background
thread is reading data from the database and updating the Customer object,
and the Customer object is bound to scene graph nodes (such as UI
controls), then there could be a violation of threading rules! For such
cases, modify the Customer object from the FX Application Thread rather
than from the background thread.
public class UpdateCustomerTask extends Task<Customer> { private final Customer customer; public UpdateCustomerTask(Customer customer) { this.customer = customer; } @Override protected Customer call() throws Exception { // pseudo-code: // query the database // read the values // Now update the customer Platform.runLater(new Runnable() { @Override public void run() { customer.setFirstName(rs.getString("FirstName")); // etc } }); return customer; } }
A Task Which Returns No Value
Many, if not most, Tasks should return a value upon completion. For
CRUD Tasks, one would expect that a "Create" Task would return the newly
created object or primary key, a "Read" Task would return the read
object, an "Update" task would return the number of records updated,
and a "Delete" task would return the number of records deleted.
However sometimes there just isn't anything truly useful to return.
For example, I might have a Task which writes to a file. Task has built
into it a mechanism for indicating whether it has succeeded or failed
along with the number of bytes written (the progress), and thus there is
nothing really for me to return. In such a case, you can use the Void
type. This is a special type in the Java language which can only be
assigned the value of null
. You would use it as follows:
final String filePath = "/foo.txt"; final String contents = "Some contents"; Task<Void> task = new Task<Void>() { @Override protected Void call() throws Exception { File file = new File(filePath); FileOutputStream out = new FileOutputStream(file); // ... and other code to write the contents ... // Return null at the end of a Task of type Void return null; } };
A Task Which Returns An ObservableList
Because the ListView, TableView, and other UI controls and scene graph
nodes make use of ObservableList, it is common to want to create and return
an ObservableList from a Task. When you do not care to display intermediate
values, the easiest way to correctly write such a Task is simply to
construct an ObservableList within the call
method, and then
return it at the conclusion of the Task.
Task<ObservableList<Rectangle>> task = new Task<ObservableList<Rectangle>>() { @Override protected ObservableList<Rectangle> call() throws Exception { updateMessage("Creating Rectangles"); ObservableList<Rectangle> results = FXCollections.observableArrayList(); for (int i=0; i<100; i++) { if (isCancelled()) break; Rectangle r = new Rectangle(10, 10); r.setX(10 * i); results.add(r); updateProgress(i, 100); } return results; } };
In the above example, we are going to create 100 rectangles and return
them from this task. An ObservableList is created within the
call
method, populated, and then returned.
A Task Which Returns Partial Results
Sometimes you want to create a Task which will return partial results.
Perhaps you are building a complex scene graph and want to show the
scene graph as it is being constructed. Or perhaps you are reading a large
amount of data over the network and want to display the entries in a
TableView as the data is arriving. In such cases, there is some shared state
available both to the FX Application Thread and the background thread.
Great care must be taken to never update shared state from any
thread other than the FX Application Thread.
The easiest way to do this is to take advantage of the updateValue(Object)
method. This method may be called repeatedly from the background thread. Updates are coalesced to prevent saturation of the FX event queue. This means you can call it as frequently as you like from the background thread but only the most recent set is ultimately set.
Task<Long> task = new Task<Long>() { @Override protected Long call() throws Exception { long a = 0; long b = 1; for (long i = 0; i < Long.MAX_VALUE; i++) { updateValue(a); a += b; b = a - b; } return a; } };
Another way to do this is to expose a new property on the Task
which will represent the partial result. Then make sure to use
Platform.runLater
when updating the partial result.
Task<Long> task = new Task<Long>() { @Override protected Long call() throws Exception { long a = 0; long b = 1; for (long i = 0; i < Long.MAX_VALUE; i++) { final long v = a; Platform.runLater(new Runnable() { @Override public void run() { updateValue(v); } } a += b; b = a - b; } return a; } };
Suppose instead of updating a single value, you want to populate an ObservableList
with results as they are obtained. One approach is to expose a new property on the Task
which will represent the partial result. Then make sure to use
Platform.runLater
when adding new items to the partial
result.
public class PartialResultsTask extends Task<ObservableList<Rectangle>> { // Uses Java 7 diamond operator private ReadOnlyObjectWrapper<ObservableList<Rectangle>> partialResults = new ReadOnlyObjectWrapper<>(this, "partialResults",
FXCollections.observableArrayList(new ArrayList<Rectangle>())); public final ObservableList<Rectangle> getPartialResults() { return partialResults.get(); } public final ReadOnlyObjectProperty<ObservableList<Rectangle>> partialResultsProperty() { return partialResults.getReadOnlyProperty(); } @Override protected ObservableList<Rectangle> call() throws Exception { updateMessage("Creating Rectangles..."); for (int i=0; i<100; i++) { if (isCancelled()) break; final Rectangle r = new Rectangle(10, 10); r.setX(10 * i); Platform.runLater(new Runnable() { @Override public void run() { partialResults.get().add(r); } }); updateProgress(i, 100); } return partialResults.get(); } }
A Task Which Modifies The Scene Graph
Generally, Tasks should not interact directly with the UI. Doing so
creates a tight coupling between a specific Task implementation and a
specific part of your UI. However, when you do want to create such a
coupling, you must ensure that you use Platform.runLater
so that any modifications of the scene graph occur on the
FX Application Thread.
final Group group = new Group(); Task<Void> task = new Task<Void>() { @Override protected Void call() throws Exception { for (int i=0; i<100; i++) { if (isCancelled()) break; final Rectangle r = new Rectangle(10, 10); r.setX(10 * i); Platform.runLater(new Runnable() { @Override public void run() { group.getChildren().add(r); } }); } return null; } };
Reacting To State Changes Generically
Sometimes you may want to write a Task which updates its progress,
message, text, or in some other way reacts whenever a state change
happens on the Task. For example, you may want to change the status
message on the Task on Failure, Success, Running, or Cancelled state changes.
Task<Integer> task = new Task<Integer>() { @Override protected Integer call() throws Exception { int iterations = 0; for (iterations = 0; iterations < 100000; iterations++) { if (isCancelled()) { break; } System.out.println("Iteration " + iterations); } return iterations; } @Override protected void succeeded() { super.succeeded(); updateMessage("Done!"); } @Override protected void cancelled() { super.cancelled(); updateMessage("Cancelled!"); } @Override protected void failed() { super.failed(); updateMessage("Failed!"); } };
Since: JavaFX 2.0
/**
* <p>
* A fully observable implementation of a {@link FutureTask}. {@code Task} exposes
* additional state and observable properties useful for programming asynchronous
* tasks in JavaFX, as defined in the {@link Worker} interface. An implementation
* of Task must override the {@link javafx.concurrent.Task#call()} method. This method
* is invoked on the background thread. Any state which is used in this method
* must be safe to read and write from a background thread. For example, manipulating
* a live scene graph from this method is unsafe and will result in runtime
* exceptions.
* </p>
* <p>
* Tasks are flexible and extremely useful for the encapsulation of "work". Because
* {@link Service} is designed to execute a Task, any Tasks defined by the application
* or library code can easily be used with a Service. Likewise, since Task extends
* from FutureTask, it is very easy and natural to use a Task with the java concurrency
* {@link java.util.concurrent.Executor} API. Since a Task is Runnable, you
* can also call it directly (by invoking the {@link javafx.concurrent.Task#run()} method)
* from another background thread. This allows for composition of work, or pass it to
* a new Thread constructed and executed manually. Finally, since you can
* manually create a new Thread, passing it a Runnable, it is possible to use
* the following idiom:
* </p>
* <pre>{@code
* Thread th = new Thread(task);
* th.setDaemon(true);
* th.start();
* }</pre>
* <p>
* Note that this code sets the daemon flag of the Thread to true. If you
* want a background thread to prevent the VM from exiting after the last
* stage is closed, then you would want daemon to be false. However, if
* you want the background threads to simply terminate after all the
* stages are closed, then you must set daemon to true.
* </p>
* <p>
* Although {@link java.util.concurrent.ExecutorService} defines several methods which
* take a Runnable, you should generally limit yourself to using the <code>execute</code>
* method inherited from {@link java.util.concurrent.Executor}.
* </p>
* <p>
* As with FutureTask, a Task is a one-shot class and cannot be reused. See {@link Service}
* for a reusable {@link Worker}.
* </p>
* <p>
* Because the Task is designed for use with JavaFX GUI applications, it ensures
* that every change to its public properties, as well as change notifications
* for state, errors, and for event handlers, all occur on the main JavaFX application
* thread. Accessing these properties from a background thread (including the
* {@link #call()} method) will result in runtime exceptions being raised. The only exception
* to this, is when initially configuring a Task, which may safely be done
* from any thread. However, once the Task has been initialized and
* started, it may only thereafter be used from the FX thread (except for those methods clearly
* marked as being appropriate for the subclass to invoke from the background thread).
* </p>
* <p>
* It is <strong>strongly encouraged</strong> that all Tasks be initialized with
* immutable state upon which the Task will operate. This should be done by providing
* a Task constructor which takes the parameters necessary for execution of the Task.
* Immutable state makes it easy and safe to use from any thread and ensures
* correctness in the presence of multiple threads.
* </p>
* <p>
* In Java there is no reliable way to "kill" a thread in process. However,
* when <code>cancel</code> is called on a Task, it is important that
* the Task stop processing. A "run-away" Task might continue processing
* and updating the message, text, and progress properties even after the
* Task has been cancelled! In Java, cancelling a Task is a cooperative
* endeavor. The user of the Task will request that it be cancelled, and
* the author of the Task must check whether is has been cancelled within
* the body of the <code>call</code> method. There are two ways this can
* be done. First, the Task author may check the isCancelled method,
* inherited from <code>FutureTask</code>, to see whether the Task has
* been cancelled. Second, if the Task implementation makes use of any
* blocking calls (such as NIO InterruptibleChannels or Thread.sleep) and
* the task is cancelled while in such a blocking call, an
* InterruptedException is thrown. Task implementations which have blocking
* calls should recognize that an interrupted thread may be the signal for
* a cancelled task and should double check the isCancelled method to ensure
* that the InterruptedException was thrown due to the cancellation of the
* Task.
* </p>
* <h2>Examples</h2>
* <p>
* The following set of examples demonstrate some of the most common uses of
* Tasks.
* </p>
*
* <h3>A Simple Loop</h3>
*
* <p>
* The first example is a simple loop that does nothing particularly useful,
* but demonstrates the fundamental aspects of writing a Task correctly. This
* example will simply loop and print to standard out on each loop iteration.
* When it completes, it returns the number of times it iterated.
* </p>
*
* <pre><code>
* {@literal Task<Integer> task = new Task<Integer>()} {
* {@literal @Override} protected Integer call() throws Exception {
* int iterations;
* {@literal for (iterations = 0; iterations < 100000; iterations++)} {
* if (isCancelled()) {
* break;
* }
* System.out.println("Iteration " + iterations);
* }
* return iterations;
* }
* };
* </code></pre>
*
* <p>
* First, we define what type of value is returned from this Task. In this
* case, we want to return the number of times we iterated, so we will
* specify the Task to be of type Integer by using generics. Then, within
* the implementation of the <code>call</code> method, we iterate from
* 0 to 100000. On each iteration, we check to see whether this Task has
* been cancelled. If it has been, then we break out of the loop and return
* the number of times we iterated. Otherwise a message is printed to
* the console and the iteration count increased and we continue looping.
* </p>
*
* <p>
* Checking for isCancelled() in the loop body is critical, otherwise the
* developer may cancel the task, but the task will continue running
* and updating both the progress and returning the incorrect result
* from the end of the <code>call</code> method. A correct implementation
* of a Task will always check for cancellation.
* </p>
*
* <h3>A Simple Loop With Progress Notification</h3>
*
* <p>
* Similar to the previous example, except this time we will modify the
* progress of the Task in each iteration. Note that we have a choice
* to make in the case of cancellation. Do we want to set the progress back
* to -1 (indeterminate) when the Task is cancelled, or do we want to leave
* the progress where it was at? In this case, let's leave the progress alone
* and only update the message on cancellation, though updating the
* progress after cancellation is a perfectly valid choice.
* </p>
*
* <pre><code>
* {@literal Task<Integer> task = new Task<Integer>()} {
* {@literal @Override} protected Integer call() throws Exception {
* int iterations;
* {@literal for (iterations = 0; iterations < 10000000; iterations++)} {
* if (isCancelled()) {
* updateMessage("Cancelled");
* break;
* }
* updateMessage("Iteration " + iterations);
* updateProgress(iterations, 10000000);
* }
* return iterations;
* }
* };
* </code></pre>
*
* <p>
* As before, within the for loop we check whether the Task has been
* cancelled. If it has been cancelled, we will update the Task's
* message to indicate that it has been cancelled, and then break as
* before. If the Task has not been cancelled, then we will update its
* message to indicate the current iteration and then update the
* progress to indicate the current progress.
* </p>
*
* <h3>A Simple Loop With Progress Notification And Blocking Calls</h3>
*
* <p>
* This example adds to the previous examples a blocking call. Because a
* blocking call may thrown an InterruptedException, and because an
* InterruptedException may occur as a result of the Task being cancelled,
* we need to be sure to handle the InterruptedException and check on the
* cancel state.
* </p>
*
* <pre><code>
* {@literal Task<Integer> task = new Task<Integer>()} {
* {@literal @Override} protected Integer call() throws Exception {
* int iterations;
* {@literal for (iterations = 0; iterations < 1000; iterations++)} {
* if (isCancelled()) {
* updateMessage("Cancelled");
* break;
* }
* updateMessage("Iteration " + iterations);
* updateProgress(iterations, 1000);
*
* // Now block the thread for a short time, but be sure
* // to check the interrupted exception for cancellation!
* try {
* Thread.sleep(100);
* } catch (InterruptedException interrupted) {
* if (isCancelled()) {
* updateMessage("Cancelled");
* break;
* }
* }
* }
* return iterations;
* }
* };
* </code></pre>
*
* <p>
* Here we have added to the body of the loop a <code>Thread.sleep</code>
* call. Since this is a blocking call, I have to handle the potential
* InterruptedException. Within the catch block, I will check whether
* the Task has been cancelled, and if so, update the message accordingly
* and break out of the loop.
* </p>
*
* <h3>A Task Which Takes Parameters</h3>
*
* <p>
* Most Tasks require some parameters in order to do useful work. For
* example, a DeleteRecordTask needs the object or primary key to delete
* from the database. A ReadFileTask needs the URI of the file to be read.
* Because Tasks operate on a background thread, care must be taken to
* make sure the body of the <code>call</code> method does not read or
* modify any shared state. There are two techniques most useful for
* doing this: using final variables, and passing variables to a Task
* during construction.
* </p>
*
* <p>
* When using a Task as an anonymous class, the most natural way to pass
* parameters to the Task is by using final variables. In this example,
* we pass to the Task the total number of times the Task should iterate.
* </p>
*
* <pre><code>
* final int totalIterations = 9000000;
* {@literal Task<Integer> task = new Task<Integer>()} {
* {@literal @Override} protected Integer call() throws Exception {
* int iterations;
* {@literal for (iterations = 0; iterations < totalIterations; iterations++)} {
* if (isCancelled()) {
* updateMessage("Cancelled");
* break;
* }
* updateMessage("Iteration " + iterations);
* updateProgress(iterations, totalIterations);
* }
* return iterations;
* }
* };
* </code></pre>
*
* <p>
* Since <code>totalIterations</code> is final, the <code>call</code>
* method can safely read it and refer to it from a background thread.
* </p>
*
* <p>
* When writing Task libraries (as opposed to specific-use implementations),
* we need to use a different technique. In this case, I will create an
* IteratingTask which performs the same work as above. This time, since
* the IteratingTask is defined in its own file, it will need to have
* parameters passed to it in its constructor. These parameters are
* assigned to final variables.
* </p>
*
* <pre><code>
* {@literal public class IteratingTask extends Task<Integer>} {
* private final int totalIterations;
*
* public IteratingTask(int totalIterations) {
* this.totalIterations = totalIterations;
* }
*
* {@literal @Override} protected Integer call() throws Exception {
* int iterations = 0;
* {@literal for (iterations = 0; iterations < totalIterations; iterations++)} {
* if (isCancelled()) {
* updateMessage("Cancelled");
* break;
* }
* updateMessage("Iteration " + iterations);
* updateProgress(iterations, totalIterations);
* }
* return iterations;
* }
* }
* </code></pre>
*
* <p>And then when used:</p>
*
* <pre>{@code
* IteratingTask task = new IteratingTask(8000000);
* }</pre>
*
* <p>In this way, parameters are passed to the IteratingTask in a safe
* manner, and again, are final. Thus, the <code>call</code> method can
* safely read this state from a background thread.</p>
*
* <p>WARNING: Do not pass mutable state to a Task and then operate on it
* from a background thread. Doing so may introduce race conditions. In
* particular, suppose you had a SaveCustomerTask which took a Customer
* in its constructor. Although the SaveCustomerTask may have a final
* reference to the Customer, if the Customer object is mutable, then it
* is possible that both the SaveCustomerTask and some other application code
* will be reading or modifying the state of the Customer from different
* threads. Be very careful in such cases, that while a mutable object such
* as this Customer is being used from a background thread, that it is
* not being used also from another thread. In particular, if the background
* thread is reading data from the database and updating the Customer object,
* and the Customer object is bound to scene graph nodes (such as UI
* controls), then there could be a violation of threading rules! For such
* cases, modify the Customer object from the FX Application Thread rather
* than from the background thread.</p>
*
* <pre><code>
* {@literal public class UpdateCustomerTask extends Task<Customer>} {
* private final Customer customer;
*
* public UpdateCustomerTask(Customer customer) {
* this.customer = customer;
* }
*
* {@literal @Override} protected Customer call() throws Exception {
* // pseudo-code:
* // query the database
* // read the values
*
* // Now update the customer
* Platform.runLater(new Runnable() {
* {@literal @Override} public void run() {
* customer.setFirstName(rs.getString("FirstName"));
* // etc
* }
* });
*
* return customer;
* }
* }
* </code></pre>
*
* <h3>A Task Which Returns No Value</h3>
*
* <p>
* Many, if not most, Tasks should return a value upon completion. For
* CRUD Tasks, one would expect that a "Create" Task would return the newly
* created object or primary key, a "Read" Task would return the read
* object, an "Update" task would return the number of records updated,
* and a "Delete" task would return the number of records deleted.
* </p>
*
* <p>
* However sometimes there just isn't anything truly useful to return.
* For example, I might have a Task which writes to a file. Task has built
* into it a mechanism for indicating whether it has succeeded or failed
* along with the number of bytes written (the progress), and thus there is
* nothing really for me to return. In such a case, you can use the Void
* type. This is a special type in the Java language which can only be
* assigned the value of <code>null</code>. You would use it as follows:
* </p>
*
* <pre><code>
* final String filePath = "/foo.txt";
* final String contents = "Some contents";
* {@literal Task<Void> task = new Task<Void>()} {
* {@literal @Override} protected Void call() throws Exception {
* File file = new File(filePath);
* FileOutputStream out = new FileOutputStream(file);
* // ... and other code to write the contents ...
*
* // Return null at the end of a Task of type Void
* return null;
* }
* };
* </code></pre>
*
* <h3>A Task Which Returns An ObservableList</h3>
*
* <p>Because the ListView, TableView, and other UI controls and scene graph
* nodes make use of ObservableList, it is common to want to create and return
* an ObservableList from a Task. When you do not care to display intermediate
* values, the easiest way to correctly write such a Task is simply to
* construct an ObservableList within the <code>call</code> method, and then
* return it at the conclusion of the Task.</p>
*
* <pre><code>
* {@literal Task<ObservableList<Rectangle>> task = new Task<ObservableList<Rectangle>>}() {
* {@literal @Override protected ObservableList<Rectangle> call() throws Exception} {
* updateMessage("Creating Rectangles");
* {@literal ObservableList<Rectangle> results = FXCollections.observableArrayList();}
* {@literal for (int i=0; i<100; i++)} {
* if (isCancelled()) break;
* Rectangle r = new Rectangle(10, 10);
* r.setX(10 * i);
* results.add(r);
* updateProgress(i, 100);
* }
* return results;
* }
* };
* </code></pre>
*
* <p>In the above example, we are going to create 100 rectangles and return
* them from this task. An ObservableList is created within the
* <code>call</code> method, populated, and then returned.</p>
*
* <h3>A Task Which Returns Partial Results</h3>
*
* <p>Sometimes you want to create a Task which will return partial results.
* Perhaps you are building a complex scene graph and want to show the
* scene graph as it is being constructed. Or perhaps you are reading a large
* amount of data over the network and want to display the entries in a
* TableView as the data is arriving. In such cases, there is some shared state
* available both to the FX Application Thread and the background thread.
* Great care must be taken to <strong>never update shared state from any
* thread other than the FX Application Thread</strong>.</p>
*
* <p>The easiest way to do this is to take advantage of the {@link #updateValue(Object)} method.
* This method may be called repeatedly from the background thread. Updates are coalesced to
* prevent saturation of the FX event queue. This means you can call it as frequently as
* you like from the background thread but only the most recent set is ultimately set.</p>
*
* <pre><code>
* {@literal Task<Long> task = new Task<Long>()} {
* {@literal @Override} protected Long call() throws Exception {
* long a = 0;
* long b = 1;
* {@literal for (long i = 0; i < Long.MAX_VALUE; i++)} {
* updateValue(a);
* a += b;
* b = a - b;
* }
* return a;
* }
* };
* </code></pre>
*
* <p>Another way to do this is to expose a new property on the Task
* which will represent the partial result. Then make sure to use
* <code>Platform.runLater</code> when updating the partial result.</p>
*
* <pre><code>
* {@literal Task<Long> task = new Task<Long>()} {
* {@literal @Override} protected Long call() throws Exception {
* long a = 0;
* long b = 1;
* {@literal for (long i = 0; i < Long.MAX_VALUE; i++)} {
* final long v = a;
* Platform.runLater(new Runnable() {
* {@literal @Override} public void run() {
* updateValue(v);
* }
* }
* a += b;
* b = a - b;
* }
* return a;
* }
* };
* </code></pre>
*
* <p>Suppose instead of updating a single value, you want to populate an ObservableList
* with results as they are obtained. One approach is to expose a new property on the Task
* which will represent the partial result. Then make sure to use
* <code>Platform.runLater</code> when adding new items to the partial
* result.</p>
*
* <pre><code>
* {@literal public class PartialResultsTask extends Task<ObservableList<Rectangle>>} {
* // Uses Java 7 diamond operator
* {@literal private ReadOnlyObjectWrapper<ObservableList<Rectangle>> partialResults =}
* {@literal new ReadOnlyObjectWrapper<>(this, "partialResults",
* FXCollections.observableArrayList(new ArrayList<Rectangle>()));}
*
* {@literal public final ObservableList<Rectangle> getPartialResults()} { return partialResults.get(); }
* {@literal public final ReadOnlyObjectProperty<ObservableList<Rectangle>> partialResultsProperty()} {
* return partialResults.getReadOnlyProperty();
* }
*
* {@literal @Override protected ObservableList<Rectangle> call() throws Exception} {
* updateMessage("Creating Rectangles...");
* {@literal for (int i=0; i<100; i++)} {
* if (isCancelled()) break;
* final Rectangle r = new Rectangle(10, 10);
* r.setX(10 * i);
* Platform.runLater(new Runnable() {
* {@literal @Override} public void run() {
* partialResults.get().add(r);
* }
* });
* updateProgress(i, 100);
* }
* return partialResults.get();
* }
* }
* </code></pre>
*
* <h3>A Task Which Modifies The Scene Graph</h3>
*
* <p>Generally, Tasks should not interact directly with the UI. Doing so
* creates a tight coupling between a specific Task implementation and a
* specific part of your UI. However, when you do want to create such a
* coupling, you must ensure that you use <code>Platform.runLater</code>
* so that any modifications of the scene graph occur on the
* FX Application Thread.</p>
*
* <pre><code>
* final Group group = new Group();
* {@literal Task<Void> task = new Task<Void>()} {
* {@literal @Override} protected Void call() throws Exception {
* {@literal for (int i=0; i<100; i++)} {
* if (isCancelled()) break;
* final Rectangle r = new Rectangle(10, 10);
* r.setX(10 * i);
* Platform.runLater(new Runnable() {
* {@literal @Override} public void run() {
* group.getChildren().add(r);
* }
* });
* }
* return null;
* }
* };
* </code></pre>
*
* <h3>Reacting To State Changes Generically</h3>
*
* <p>Sometimes you may want to write a Task which updates its progress,
* message, text, or in some other way reacts whenever a state change
* happens on the Task. For example, you may want to change the status
* message on the Task on Failure, Success, Running, or Cancelled state changes.
* </p>
* <pre><code>
* {@literal Task<Integer> task = new Task<Integer>()} {
* {@literal @Override} protected Integer call() throws Exception {
* int iterations = 0;
* {@literal for (iterations = 0; iterations < 100000; iterations++)} {
* if (isCancelled()) {
* break;
* }
* System.out.println("Iteration " + iterations);
* }
* return iterations;
* }
*
* {@literal @Override} protected void succeeded() {
* super.succeeded();
* updateMessage("Done!");
* }
*
* {@literal @Override} protected void cancelled() {
* super.cancelled();
* updateMessage("Cancelled!");
* }
*
* {@literal @Override} protected void failed() {
* super.failed();
* updateMessage("Failed!");
* }
* };
* </code></pre>
* @since JavaFX 2.0
*/
public abstract class Task<V> extends FutureTask<V> implements Worker<V>, EventTarget {
Used to send workDone updates in a thread-safe manner from the subclass
to the FX application thread and workDone related properties. AtomicReference
is used so as to coalesce updates such that we don't flood the event queue.
/**
* Used to send workDone updates in a thread-safe manner from the subclass
* to the FX application thread and workDone related properties. AtomicReference
* is used so as to coalesce updates such that we don't flood the event queue.
*/
private AtomicReference<ProgressUpdate> progressUpdate = new AtomicReference<>();
Used to send message updates in a thread-safe manner from the subclass
to the FX application thread. AtomicReference is used so as to coalesce
updates such that we don't flood the event queue.
/**
* Used to send message updates in a thread-safe manner from the subclass
* to the FX application thread. AtomicReference is used so as to coalesce
* updates such that we don't flood the event queue.
*/
private AtomicReference<String> messageUpdate = new AtomicReference<>();
Used to send title updates in a thread-safe manner from the subclass
to the FX application thread. AtomicReference is used so as to coalesce
updates such that we don't flood the event queue.
/**
* Used to send title updates in a thread-safe manner from the subclass
* to the FX application thread. AtomicReference is used so as to coalesce
* updates such that we don't flood the event queue.
*/
private AtomicReference<String> titleUpdate = new AtomicReference<>();
Used to send value updates in a thread-safe manner from the subclass
to the FX application thread. AtomicReference is used so as to coalesce
updates such that we don't flood the event queue.
/**
* Used to send value updates in a thread-safe manner from the subclass
* to the FX application thread. AtomicReference is used so as to coalesce
* updates such that we don't flood the event queue.
*/
private AtomicReference<V> valueUpdate = new AtomicReference<>();
This is used so we have a thread-safe way to ask whether the task was
started in the checkThread() method.
/**
* This is used so we have a thread-safe way to ask whether the task was
* started in the checkThread() method.
*/
private volatile boolean started = false;
Creates a new Task.
/**
* Creates a new Task.
*/
public Task() {
this(new TaskCallable<V>());
}
This bit of construction trickery is necessary because otherwise there is
no way for the main constructor to both create the callable and maintain
a reference to it, which is necessary because an anonymous callable construction
cannot reference the implicit "this". We leverage an internal Callable
so that all the pre-built semantics around cancel and so forth are
handled correctly.
Params: - callableAdapter – non-null implementation of the
TaskCallable adapter
/**
* This bit of construction trickery is necessary because otherwise there is
* no way for the main constructor to both create the callable and maintain
* a reference to it, which is necessary because an anonymous callable construction
* cannot reference the implicit "this". We leverage an internal Callable
* so that all the pre-built semantics around cancel and so forth are
* handled correctly.
*
* @param callableAdapter non-null implementation of the
* TaskCallable adapter
*/
private Task(final TaskCallable<V> callableAdapter) {
super(callableAdapter);
callableAdapter.task = this;
}
Invoked when the Task is executed, the call method must be overridden and
implemented by subclasses. The call method actually performs the
background thread logic. Only the updateProgress, updateMessage, updateValue and
updateTitle methods of Task may be called from code within this method.
Any other interaction with the Task from the background thread will result
in runtime exceptions.
Throws: - Exception – an unhandled exception which occurred during the
background operation
Returns: The result of the background work, if any.
/**
* Invoked when the Task is executed, the call method must be overridden and
* implemented by subclasses. The call method actually performs the
* background thread logic. Only the updateProgress, updateMessage, updateValue and
* updateTitle methods of Task may be called from code within this method.
* Any other interaction with the Task from the background thread will result
* in runtime exceptions.
*
* @return The result of the background work, if any.
* @throws Exception an unhandled exception which occurred during the
* background operation
*/
protected abstract V call() throws Exception;
private ObjectProperty<State> state = new SimpleObjectProperty<>(this, "state", State.READY);
final void setState(State value) { // package access for the Service
checkThread();
final State s = getState();
if (s != State.CANCELLED) {
this.state.set(value);
// Make sure the running flag is set
setRunning(value == State.SCHEDULED || value == State.RUNNING);
// Invoke the event handlers, and then call the protected methods.
switch (state.get()) {
case CANCELLED:
fireEvent(new WorkerStateEvent(this, WORKER_STATE_CANCELLED));
cancelled();
break;
case FAILED:
fireEvent(new WorkerStateEvent(this, WORKER_STATE_FAILED));
failed();
break;
case READY:
// This even can never meaningfully occur, because the
// Task begins life as ready and can never go back to it!
break;
case RUNNING:
fireEvent(new WorkerStateEvent(this, WORKER_STATE_RUNNING));
running();
break;
case SCHEDULED:
fireEvent(new WorkerStateEvent(this, WORKER_STATE_SCHEDULED));
scheduled();
break;
case SUCCEEDED:
fireEvent(new WorkerStateEvent(this, WORKER_STATE_SUCCEEDED));
succeeded();
break;
default: throw new AssertionError("Should be unreachable");
}
}
}
@Override public final State getState() { checkThread(); return state.get(); }
@Override public final ReadOnlyObjectProperty<State> stateProperty() { checkThread(); return state; }
The onSchedule event handler is called whenever the Task state
transitions to the SCHEDULED state.
Returns: the onScheduled event handler property Since: JavaFX 2.1
/**
* The onSchedule event handler is called whenever the Task state
* transitions to the SCHEDULED state.
*
* @return the onScheduled event handler property
* @since JavaFX 2.1
*/
public final ObjectProperty<EventHandler<WorkerStateEvent>> onScheduledProperty() {
checkThread();
return getEventHelper().onScheduledProperty();
}
The onSchedule event handler is called whenever the Task state
transitions to the SCHEDULED state.
Returns: the onScheduled event handler, if any Since: JavaFX 2.1
/**
* The onSchedule event handler is called whenever the Task state
* transitions to the SCHEDULED state.
*
* @return the onScheduled event handler, if any
* @since JavaFX 2.1
*/
public final EventHandler<WorkerStateEvent> getOnScheduled() {
checkThread();
return eventHelper == null ? null : eventHelper.getOnScheduled();
}
The onSchedule event handler is called whenever the Task state
transitions to the SCHEDULED state.
Params: - value – the event handler, can be null to clear it
Since: JavaFX 2.1
/**
* The onSchedule event handler is called whenever the Task state
* transitions to the SCHEDULED state.
*
* @param value the event handler, can be null to clear it
* @since JavaFX 2.1
*/
public final void setOnScheduled(EventHandler<WorkerStateEvent> value) {
checkThread();
getEventHelper().setOnScheduled(value);
}
A protected convenience method for subclasses, called whenever the
state of the Task has transitioned to the SCHEDULED state.
This method is invoked on the FX Application Thread after the Task has been fully transitioned to
the new state.
Since: JavaFX 2.1
/**
* A protected convenience method for subclasses, called whenever the
* state of the Task has transitioned to the SCHEDULED state.
* This method is invoked on the FX Application Thread after the Task has been fully transitioned to
* the new state.
* @since JavaFX 2.1
*/
protected void scheduled() { }
The onRunning event handler is called whenever the Task state
transitions to the RUNNING state.
Returns: the onRunning event handler property Since: JavaFX 2.1
/**
* The onRunning event handler is called whenever the Task state
* transitions to the RUNNING state.
*
* @return the onRunning event handler property
* @since JavaFX 2.1
*/
public final ObjectProperty<EventHandler<WorkerStateEvent>> onRunningProperty() {
checkThread();
return getEventHelper().onRunningProperty();
}
The onRunning event handler is called whenever the Task state
transitions to the RUNNING state.
Returns: the onRunning event handler, if any Since: JavaFX 2.1
/**
* The onRunning event handler is called whenever the Task state
* transitions to the RUNNING state.
*
* @return the onRunning event handler, if any
* @since JavaFX 2.1
*/
public final EventHandler<WorkerStateEvent> getOnRunning() {
checkThread();
return eventHelper == null ? null : eventHelper.getOnRunning();
}
The onRunning event handler is called whenever the Task state
transitions to the RUNNING state.
Params: - value – the event handler, can be null to clear it
Since: JavaFX 2.1
/**
* The onRunning event handler is called whenever the Task state
* transitions to the RUNNING state.
*
* @param value the event handler, can be null to clear it
* @since JavaFX 2.1
*/
public final void setOnRunning(EventHandler<WorkerStateEvent> value) {
checkThread();
getEventHelper().setOnRunning(value);
}
A protected convenience method for subclasses, called whenever the
state of the Task has transitioned to the RUNNING state.
This method is invoked on the FX Application Thread after the Task has been fully transitioned to
the new state.
Since: JavaFX 2.1
/**
* A protected convenience method for subclasses, called whenever the
* state of the Task has transitioned to the RUNNING state.
* This method is invoked on the FX Application Thread after the Task has been fully transitioned to
* the new state.
* @since JavaFX 2.1
*/
protected void running() { }
The onSucceeded event handler is called whenever the Task state
transitions to the SUCCEEDED state.
Returns: the onSucceeded event handler property Since: JavaFX 2.1
/**
* The onSucceeded event handler is called whenever the Task state
* transitions to the SUCCEEDED state.
*
* @return the onSucceeded event handler property
* @since JavaFX 2.1
*/
public final ObjectProperty<EventHandler<WorkerStateEvent>> onSucceededProperty() {
checkThread();
return getEventHelper().onSucceededProperty();
}
The onSucceeded event handler is called whenever the Task state
transitions to the SUCCEEDED state.
Returns: the onSucceeded event handler, if any Since: JavaFX 2.1
/**
* The onSucceeded event handler is called whenever the Task state
* transitions to the SUCCEEDED state.
*
* @return the onSucceeded event handler, if any
* @since JavaFX 2.1
*/
public final EventHandler<WorkerStateEvent> getOnSucceeded() {
checkThread();
return eventHelper == null ? null : eventHelper.getOnSucceeded();
}
The onSucceeded event handler is called whenever the Task state
transitions to the SUCCEEDED state.
Params: - value – the event handler, can be null to clear it
Since: JavaFX 2.1
/**
* The onSucceeded event handler is called whenever the Task state
* transitions to the SUCCEEDED state.
*
* @param value the event handler, can be null to clear it
* @since JavaFX 2.1
*/
public final void setOnSucceeded(EventHandler<WorkerStateEvent> value) {
checkThread();
getEventHelper().setOnSucceeded(value);
}
A protected convenience method for subclasses, called whenever the
state of the Task has transitioned to the SUCCEEDED state.
This method is invoked on the FX Application Thread after the Task has been fully transitioned to
the new state.
Since: JavaFX 2.1
/**
* A protected convenience method for subclasses, called whenever the
* state of the Task has transitioned to the SUCCEEDED state.
* This method is invoked on the FX Application Thread after the Task has been fully transitioned to
* the new state.
* @since JavaFX 2.1
*/
protected void succeeded() { }
The onCancelled event handler is called whenever the Task state
transitions to the CANCELLED state.
Returns: the onCancelled event handler property Since: JavaFX 2.1
/**
* The onCancelled event handler is called whenever the Task state
* transitions to the CANCELLED state.
*
* @return the onCancelled event handler property
* @since JavaFX 2.1
*/
public final ObjectProperty<EventHandler<WorkerStateEvent>> onCancelledProperty() {
checkThread();
return getEventHelper().onCancelledProperty();
}
The onCancelled event handler is called whenever the Task state
transitions to the CANCELLED state.
Returns: the onCancelled event handler, if any Since: JavaFX 2.1
/**
* The onCancelled event handler is called whenever the Task state
* transitions to the CANCELLED state.
*
* @return the onCancelled event handler, if any
* @since JavaFX 2.1
*/
public final EventHandler<WorkerStateEvent> getOnCancelled() {
checkThread();
return eventHelper == null ? null : eventHelper.getOnCancelled();
}
The onCancelled event handler is called whenever the Task state
transitions to the CANCELLED state.
Params: - value – the event handler, can be null to clear it
Since: JavaFX 2.1
/**
* The onCancelled event handler is called whenever the Task state
* transitions to the CANCELLED state.
*
* @param value the event handler, can be null to clear it
* @since JavaFX 2.1
*/
public final void setOnCancelled(EventHandler<WorkerStateEvent> value) {
checkThread();
getEventHelper().setOnCancelled(value);
}
A protected convenience method for subclasses, called whenever the
state of the Task has transitioned to the CANCELLED state.
This method is invoked on the FX Application Thread after the Task has been fully transitioned to
the new state.
Since: JavaFX 2.1
/**
* A protected convenience method for subclasses, called whenever the
* state of the Task has transitioned to the CANCELLED state.
* This method is invoked on the FX Application Thread after the Task has been fully transitioned to
* the new state.
* @since JavaFX 2.1
*/
protected void cancelled() { }
The onFailed event handler is called whenever the Task state
transitions to the FAILED state.
Returns: the onFailed event handler property Since: JavaFX 2.1
/**
* The onFailed event handler is called whenever the Task state
* transitions to the FAILED state.
*
* @return the onFailed event handler property
* @since JavaFX 2.1
*/
public final ObjectProperty<EventHandler<WorkerStateEvent>> onFailedProperty() {
checkThread();
return getEventHelper().onFailedProperty();
}
The onFailed event handler is called whenever the Task state
transitions to the FAILED state.
Returns: the onFailed event handler, if any Since: JavaFX 2.1
/**
* The onFailed event handler is called whenever the Task state
* transitions to the FAILED state.
*
* @return the onFailed event handler, if any
* @since JavaFX 2.1
*/
public final EventHandler<WorkerStateEvent> getOnFailed() {
checkThread();
return eventHelper == null ? null : eventHelper.getOnFailed();
}
The onFailed event handler is called whenever the Task state
transitions to the FAILED state.
Params: - value – the event handler, can be null to clear it
Since: JavaFX 2.1
/**
* The onFailed event handler is called whenever the Task state
* transitions to the FAILED state.
*
* @param value the event handler, can be null to clear it
* @since JavaFX 2.1
*/
public final void setOnFailed(EventHandler<WorkerStateEvent> value) {
checkThread();
getEventHelper().setOnFailed(value);
}
A protected convenience method for subclasses, called whenever the
state of the Task has transitioned to the FAILED state.
This method is invoked on the FX Application Thread after the Task has been fully transitioned to
the new state.
Since: JavaFX 2.1
/**
* A protected convenience method for subclasses, called whenever the
* state of the Task has transitioned to the FAILED state.
* This method is invoked on the FX Application Thread after the Task has been fully transitioned to
* the new state.
* @since JavaFX 2.1
*/
protected void failed() { }
private final ObjectProperty<V> value = new SimpleObjectProperty<>(this, "value");
private void setValue(V v) { checkThread(); value.set(v); }
@Override public final V getValue() { checkThread(); return value.get(); }
@Override public final ReadOnlyObjectProperty<V> valueProperty() { checkThread(); return value; }
private final ObjectProperty<Throwable> exception = new SimpleObjectProperty<>(this, "exception");
private void _setException(Throwable value) { checkThread(); exception.set(value); }
@Override public final Throwable getException() { checkThread(); return exception.get(); }
@Override public final ReadOnlyObjectProperty<Throwable> exceptionProperty() { checkThread(); return exception; }
private final DoubleProperty workDone = new SimpleDoubleProperty(this, "workDone", -1);
private void setWorkDone(double value) { checkThread(); workDone.set(value); }
@Override public final double getWorkDone() { checkThread(); return workDone.get(); }
@Override public final ReadOnlyDoubleProperty workDoneProperty() { checkThread(); return workDone; }
private final DoubleProperty totalWork = new SimpleDoubleProperty(this, "totalWork", -1);
private void setTotalWork(double value) { checkThread(); totalWork.set(value); }
@Override public final double getTotalWork() { checkThread(); return totalWork.get(); }
@Override public final ReadOnlyDoubleProperty totalWorkProperty() { checkThread(); return totalWork; }
private final DoubleProperty progress = new SimpleDoubleProperty(this, "progress", -1);
private void setProgress(double value) { checkThread(); progress.set(value); }
@Override public final double getProgress() { checkThread(); return progress.get(); }
@Override public final ReadOnlyDoubleProperty progressProperty() { checkThread(); return progress; }
private final BooleanProperty running = new SimpleBooleanProperty(this, "running", false);
private void setRunning(boolean value) { checkThread(); running.set(value); }
@Override public final boolean isRunning() { checkThread(); return running.get(); }
@Override public final ReadOnlyBooleanProperty runningProperty() { checkThread(); return running; }
private final StringProperty message = new SimpleStringProperty(this, "message", "");
@Override public final String getMessage() { checkThread(); return message.get(); }
@Override public final ReadOnlyStringProperty messageProperty() { checkThread(); return message; }
private final StringProperty title = new SimpleStringProperty(this, "title", "");
@Override public final String getTitle() { checkThread(); return title.get(); }
@Override public final ReadOnlyStringProperty titleProperty() { checkThread(); return title; }
@Override public final boolean cancel() {
return cancel(true);
}
// Need to assert the modifyThread permission so an app can cancel
// a task that it created (the default executor for the service runs in
// its own thread group)
// Note that this is needed when running with a security manager.
private static final Permission modifyThreadPerm = new RuntimePermission("modifyThread");
@Override public boolean cancel(boolean mayInterruptIfRunning) {
// Delegate to the super implementation to actually attempt to cancel this thing
// Assert the modifyThread permission
boolean flag = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) () -> super.cancel(mayInterruptIfRunning),
null,
modifyThreadPerm);
// If cancel succeeded (according to the semantics of the Future cancel method),
// then we need to make sure the State flag is set appropriately
if (flag) {
// If this method was called on the FX application thread, then we can
// just update the state directly and this will make sure that after
// the cancel method was called, the state will be set correctly
// (otherwise it would be indeterminate). However if the cancel method was
// called off the FX app thread, then we must use runLater, and the
// 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()) {
setState(State.CANCELLED);
} else {
runLater(() -> setState(State.CANCELLED));
}
}
// return the flag
return flag;
}
Updates the workDone
, totalWork
,
and progress
properties. Calls to updateProgress
are coalesced and run later on the FX application thread, and calls
to updateProgress, even from the FX Application thread, may not
necessarily result in immediate updates to these properties, and
intermediate workDone values may be coalesced to save on event
notifications. max
becomes the new value for
totalWork
.
This method is safe to be called from any thread.
Params: - workDone – A value from Long.MIN_VALUE up to max. If the value is greater
than max, then it will be clamped at max.
If the value passed is negative then the resulting percent
done will be -1 (thus, indeterminate).
- max – A value from Long.MIN_VALUE to Long.MAX_VALUE.
See Also:
/**
* Updates the <code>workDone</code>, <code>totalWork</code>,
* and <code>progress</code> properties. Calls to updateProgress
* are coalesced and run later on the FX application thread, and calls
* to updateProgress, even from the FX Application thread, may not
* necessarily result in immediate updates to these properties, and
* intermediate workDone values may be coalesced to save on event
* notifications. <code>max</code> becomes the new value for
* <code>totalWork</code>.
* <p>
* <em>This method is safe to be called from any thread.</em>
* </p>
*
* @param workDone A value from Long.MIN_VALUE up to max. If the value is greater
* than max, then it will be clamped at max.
* If the value passed is negative then the resulting percent
* done will be -1 (thus, indeterminate).
* @param max A value from Long.MIN_VALUE to Long.MAX_VALUE.
* @see #updateProgress(double, double)
*/
protected void updateProgress(long workDone, long max) {
updateProgress((double)workDone, (double)max);
}
Updates the workDone
, totalWork
,
and progress
properties. Calls to updateProgress
are coalesced and run later on the FX application thread, and calls
to updateProgress, even from the FX Application thread, may not
necessarily result in immediate updates to these properties, and
intermediate workDone values may be coalesced to save on event
notifications. max
becomes the new value for
totalWork
.
This method is safe to be called from any thread.
Params: - workDone – A value from Double.MIN_VALUE up to max. If the value is greater
than max, then it will be clamped at max.
If the value passed is negative, or Infinity, or NaN,
then the resulting percentDone will be -1 (thus, indeterminate).
- max – A value from Double.MIN_VALUE to Double.MAX_VALUE. Infinity and NaN are treated as -1.
Since: JavaFX 2.2
/**
* Updates the <code>workDone</code>, <code>totalWork</code>,
* and <code>progress</code> properties. Calls to updateProgress
* are coalesced and run later on the FX application thread, and calls
* to updateProgress, even from the FX Application thread, may not
* necessarily result in immediate updates to these properties, and
* intermediate workDone values may be coalesced to save on event
* notifications. <code>max</code> becomes the new value for
* <code>totalWork</code>.
* <p>
* <em>This method is safe to be called from any thread.</em>
* </p>
*
* @param workDone A value from Double.MIN_VALUE up to max. If the value is greater
* than max, then it will be clamped at max.
* If the value passed is negative, or Infinity, or NaN,
* then the resulting percentDone will be -1 (thus, indeterminate).
* @param max A value from Double.MIN_VALUE to Double.MAX_VALUE. Infinity and NaN are treated as -1.
* @since JavaFX 2.2
*/
protected void updateProgress(double workDone, double max) {
// Adjust Infinity / NaN to be -1 for both workDone and max.
if (Double.isInfinite(workDone) || Double.isNaN(workDone)) {
workDone = -1;
}
if (Double.isInfinite(max) || Double.isNaN(max)) {
max = -1;
}
if (workDone < 0) {
workDone = -1;
}
if (max < 0) {
max = -1;
}
// Clamp the workDone if necessary so as not to exceed max
if (workDone > max) {
workDone = max;
}
if (isFxApplicationThread()) {
_updateProgress(workDone, max);
} else if (progressUpdate.getAndSet(new ProgressUpdate(workDone, max)) == null) {
runLater(() -> {
final ProgressUpdate update = progressUpdate.getAndSet(null);
_updateProgress(update.workDone, update.totalWork);
});
}
}
private void _updateProgress(double workDone, double max) {
setTotalWork(max);
setWorkDone(workDone);
if (workDone == -1) {
setProgress(-1);
} else {
setProgress(workDone / max);
}
}
Updates the message
property. Calls to updateMessage
are coalesced and run later on the FX application thread, so calls
to updateMessage, even from the FX Application thread, may not
necessarily result in immediate updates to this property, and
intermediate message values may be coalesced to save on event
notifications.
This method is safe to be called from any thread.
Params: - message – the new message
/**
* Updates the <code>message</code> property. Calls to updateMessage
* are coalesced and run later on the FX application thread, so calls
* to updateMessage, even from the FX Application thread, may not
* necessarily result in immediate updates to this property, and
* intermediate message values may be coalesced to save on event
* notifications.
* <p>
* <em>This method is safe to be called from any thread.</em>
* </p>
*
* @param message the new message
*/
protected void updateMessage(String message) {
if (isFxApplicationThread()) {
this.message.set(message);
} else {
// As with the workDone, it might be that the background thread
// will update this message quite frequently, and we need
// to throttle the updates so as not to completely clobber
// the event dispatching system.
if (messageUpdate.getAndSet(message) == null) {
runLater(new Runnable() {
@Override public void run() {
final String message = messageUpdate.getAndSet(null);
Task.this.message.set(message);
}
});
}
}
}
Updates the title
property. Calls to updateTitle
are coalesced and run later on the FX application thread, so calls
to updateTitle, even from the FX Application thread, may not
necessarily result in immediate updates to this property, and
intermediate title values may be coalesced to save on event
notifications.
This method is safe to be called from any thread.
Params: - title – the new title
/**
* Updates the <code>title</code> property. Calls to updateTitle
* are coalesced and run later on the FX application thread, so calls
* to updateTitle, even from the FX Application thread, may not
* necessarily result in immediate updates to this property, and
* intermediate title values may be coalesced to save on event
* notifications.
* <p>
* <em>This method is safe to be called from any thread.</em>
* </p>
*
* @param title the new title
*/
protected void updateTitle(String title) {
if (isFxApplicationThread()) {
this.title.set(title);
} else {
// As with the workDone, it might be that the background thread
// will update this title quite frequently, and we need
// to throttle the updates so as not to completely clobber
// the event dispatching system.
if (titleUpdate.getAndSet(title) == null) {
runLater(new Runnable() {
@Override public void run() {
final String title = titleUpdate.getAndSet(null);
Task.this.title.set(title);
}
});
}
}
}
Updates the value
property. Calls to updateValue
are coalesced and run later on the FX application thread, so calls
to updateValue, even from the FX Application thread, may not
necessarily result in immediate updates to this property, and
intermediate values may be coalesced to save on event
notifications.
This method is safe to be called from any thread.
Params: - value – the new value
Since: JavaFX 8.0
/**
* Updates the <code>value</code> property. Calls to updateValue
* are coalesced and run later on the FX application thread, so calls
* to updateValue, even from the FX Application thread, may not
* necessarily result in immediate updates to this property, and
* intermediate values may be coalesced to save on event
* notifications.
* <p>
* <em>This method is safe to be called from any thread.</em>
* </p>
*
* @param value the new value
* @since JavaFX 8.0
*/
protected void updateValue(V value) {
if (isFxApplicationThread()) {
this.value.set(value);
} else {
// As with the workDone, it might be that the background thread
// will update this value quite frequently, and we need
// to throttle the updates so as not to completely clobber
// the event dispatching system.
if (valueUpdate.getAndSet(value) == null) {
runLater(() -> Task.this.value.set(valueUpdate.getAndSet(null)));
}
}
}
/*
* IMPLEMENTATION
*/
private void checkThread() {
if (started && !isFxApplicationThread()) {
throw new IllegalStateException("Task must only be used from the FX Application Thread");
}
}
// This method exists for the sake of testing, so I can subclass and override
// this method in the test and not actually use Platform.runLater.
void runLater(Runnable r) {
Platform.runLater(r);
}
// This method exists for the sake of testing, so I can subclass and override
// this method in the test and not actually use Platform.isFxApplicationThread.
boolean isFxApplicationThread() {
return Platform.isFxApplicationThread();
}
*
Event Dispatch *
*
/***************************************************************************
* *
* Event Dispatch *
* *
**************************************************************************/
private EventHelper eventHelper = null;
private EventHelper getEventHelper() {
if (eventHelper == null) {
eventHelper = new EventHelper(this);
}
return eventHelper;
}
Registers an event handler to this task. Any event filters are first
processed, then the specified onFoo event handlers, and finally any
event handlers registered by this method. As with other events
in the scene graph, if an event is consumed, it will not continue
dispatching.
Params: - eventType – the type of the events to receive by the handler
- eventHandler – the handler to register
Type parameters: - <T> – the specific event class of the handler
Throws: - NullPointerException – if the event type or handler is null
Since: JavaFX 2.1
/**
* Registers an event handler to this task. Any event filters are first
* processed, then the specified onFoo event handlers, and finally any
* event handlers registered by this method. As with other events
* in the scene graph, if an event is consumed, it will not continue
* dispatching.
*
* @param <T> the specific event class of the handler
* @param eventType the type of the events to receive by the handler
* @param eventHandler the handler to register
* @throws NullPointerException if the event type or handler is null
* @since JavaFX 2.1
*/
public final <T extends Event> void addEventHandler(
final EventType<T> eventType,
final EventHandler<? super T> eventHandler) {
checkThread();
getEventHelper().addEventHandler(eventType, eventHandler);
}
Unregisters a previously registered event handler from this task. One
handler might have been registered for different event types, so the
caller needs to specify the particular event type from which to
unregister the handler.
Params: - eventType – the event type from which to unregister
- eventHandler – the handler to unregister
Type parameters: - <T> – the specific event class of the handler
Throws: - NullPointerException – if the event type or handler is null
Since: JavaFX 2.1
/**
* Unregisters a previously registered event handler from this task. One
* handler might have been registered for different event types, so the
* caller needs to specify the particular event type from which to
* unregister the handler.
*
* @param <T> the specific event class of the handler
* @param eventType the event type from which to unregister
* @param eventHandler the handler to unregister
* @throws NullPointerException if the event type or handler is null
* @since JavaFX 2.1
*/
public final <T extends Event> void removeEventHandler(
final EventType<T> eventType,
final EventHandler<? super T> eventHandler) {
checkThread();
getEventHelper().removeEventHandler(eventType, eventHandler);
}
Registers an event filter to this task. Registered event filters get
an event before any associated event handlers.
Params: - eventType – the type of the events to receive by the filter
- eventFilter – the filter to register
Type parameters: - <T> – the specific event class of the filter
Throws: - NullPointerException – if the event type or filter is null
Since: JavaFX 2.1
/**
* Registers an event filter to this task. Registered event filters get
* an event before any associated event handlers.
*
* @param <T> the specific event class of the filter
* @param eventType the type of the events to receive by the filter
* @param eventFilter the filter to register
* @throws NullPointerException if the event type or filter is null
* @since JavaFX 2.1
*/
public final <T extends Event> void addEventFilter(
final EventType<T> eventType,
final EventHandler<? super T> eventFilter) {
checkThread();
getEventHelper().addEventFilter(eventType, eventFilter);
}
Unregisters a previously registered event filter from this task. One
filter might have been registered for different event types, so the
caller needs to specify the particular event type from which to
unregister the filter.
Params: - eventType – the event type from which to unregister
- eventFilter – the filter to unregister
Type parameters: - <T> – the specific event class of the filter
Throws: - NullPointerException – if the event type or filter is null
Since: JavaFX 2.1
/**
* Unregisters a previously registered event filter from this task. One
* filter might have been registered for different event types, so the
* caller needs to specify the particular event type from which to
* unregister the filter.
*
* @param <T> the specific event class of the filter
* @param eventType the event type from which to unregister
* @param eventFilter the filter to unregister
* @throws NullPointerException if the event type or filter is null
* @since JavaFX 2.1
*/
public final <T extends Event> void removeEventFilter(
final EventType<T> eventType,
final EventHandler<? super T> eventFilter) {
checkThread();
getEventHelper().removeEventFilter(eventType, eventFilter);
}
Sets the handler to use for this event type. There can only be one such
handler specified at a time. This handler is guaranteed to be called
first. This is used for registering the user-defined onFoo event
handlers.
Params: - eventType – the event type to associate with the given eventHandler
- eventHandler – the handler to register, or null to unregister
Type parameters: - <T> – the specific event class of the handler
Throws: - NullPointerException – if the event type is null
Since: JavaFX 2.1
/**
* Sets the handler to use for this event type. There can only be one such
* handler specified at a time. This handler is guaranteed to be called
* first. This is used for registering the user-defined onFoo event
* handlers.
*
* @param <T> the specific event class of the handler
* @param eventType the event type to associate with the given eventHandler
* @param eventHandler the handler to register, or null to unregister
* @throws NullPointerException if the event type is null
* @since JavaFX 2.1
*/
protected final <T extends Event> void setEventHandler(
final EventType<T> eventType,
final EventHandler<? super T> eventHandler) {
checkThread();
getEventHelper().setEventHandler(eventType, eventHandler);
}
Fires the specified event. Any event filter encountered will
be notified and can consume the event. If not consumed by the filters,
the event handlers on this task are notified. If these don't consume the
event either, then all event handlers are called and can consume the
event.
This method must be called on the FX user thread.
Params: - event – the event to fire
Since: JavaFX 2.1
/**
* Fires the specified event. Any event filter encountered will
* be notified and can consume the event. If not consumed by the filters,
* the event handlers on this task are notified. If these don't consume the
* event either, then all event handlers are called and can consume the
* event.
* <p>
* This method must be called on the FX user thread.
*
* @param event the event to fire
* @since JavaFX 2.1
*/
public final void fireEvent(Event event) {
checkThread();
getEventHelper().fireEvent(event);
}
@Override
public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) {
checkThread();
return getEventHelper().buildEventDispatchChain(tail);
}
A struct like class that contains the last workDone update information.
What we do when updateProgress is called, is we create a new ProgressUpdate
object and store it. If it was null, then we fire off a new Runnable
using RunLater, which will eventually read the latest and set it to null
atomically. If it was not null, then we simply update it.
/**
* A struct like class that contains the last workDone update information.
* What we do when updateProgress is called, is we create a new ProgressUpdate
* object and store it. If it was null, then we fire off a new Runnable
* using RunLater, which will eventually read the latest and set it to null
* atomically. If it was not null, then we simply update it.
*/
private static final class ProgressUpdate {
private final double workDone;
private final double totalWork;
private ProgressUpdate(double p, double m) {
this.workDone = p;
this.totalWork = m;
}
}
TaskCallable actually implements the Callable contract as defined for
the FutureTask class, and is necessary so as to allow us to intercept
the call() operation to update state on the Task as appropriate.
Type parameters: - <V> –
/**
* TaskCallable actually implements the Callable contract as defined for
* the FutureTask class, and is necessary so as to allow us to intercept
* the call() operation to update state on the Task as appropriate.
* @param <V>
*/
private static final class TaskCallable<V> implements Callable<V> {
The Task that is going to use this TaskCallable
/**
* The Task that is going to use this TaskCallable
*/
private Task<V> task;
Create a TaskCallable. The concurrent and other fields MUST be set
immediately after creation.
/**
* Create a TaskCallable. The concurrent and other fields MUST be set
* immediately after creation.
*/
private TaskCallable() { }
Invoked by the system when it is time to run the client code. This
implementation is where we modify the state and other properties
and from which we invoke the events.
Throws: - Exception – any exception which occurred
Returns: The result of the Task call method
/**
* Invoked by the system when it is time to run the client code. This
* implementation is where we modify the state and other properties
* and from which we invoke the events.
*
* @return The result of the Task call method
* @throws Exception any exception which occurred
*/
@Override public V call() throws Exception {
// If the Task is sent to an ExecutorService for execution, then we
// will need to make sure that we transition first to the SCHEDULED
// state before then transitioning to the RUNNING state. If the
// Task was executed by a Service, then it will have already been
// in the SCHEDULED state and setting it again here has no negative
// effect. But we must ensure that SCHEDULED is visited before RUNNING
// in all cases so that developer code can be consistent.
task.started = true;
task.runLater(() -> {
task.setState(State.SCHEDULED);
task.setState(State.RUNNING);
});
// Go ahead and delegate to the wrapped callable
try {
final V result = task.call();
if (!task.isCancelled()) {
// If it was not cancelled, then we take the return
// value and set it as the result.
task.runLater(() -> {
// The result must be set first, so that when the
// SUCCEEDED flag is set, the value will be available
// The alternative is not the case, because you
// can assume if the result is set, it has
// succeeded.
task.updateValue(result);
task.setState(State.SUCCEEDED);
});
return result;
} else {
// Since cancelled Future/FutureTask doesn't return any value,
// the returned value is going to be trashed, so we can jus return null
return null;
}
} catch (final Throwable th) {
// Be sure to set the state after setting the cause of failure
// so that developers handling the state change events have a
// throwable to inspect when they get the FAILED state. Note
// that the other way around is not important -- when a developer
// observes the causeOfFailure is set to a non-null value, even
// though the state has not yet been updated, he can infer that
// it will be FAILED because it can be nothing other than FAILED
// in that circumstance.
task.runLater(() -> {
task._setException(th);
task.setState(State.FAILED);
});
// Some error occurred during the call (it might be
// an exception (either runtime or checked), or it might
// be an error. In any case, we capture the throwable,
// record it as the causeOfFailure, and then rethrow. However
// since the Callable interface requires that we throw an
// Exception (not Throwable), we have to wrap the exception
// if it is not already one.
if (th instanceof Exception) {
throw (Exception) th;
} else {
throw new Exception(th);
}
}
}
}
}