Force stop Java Files.copy() running on external thread Force stop Java Files.copy() running on external thread multithreading multithreading

Force stop Java Files.copy() running on external thread


I strongly encourage you to use a FileChannel.It has the transferFrom() method which returns immediately when the thread running it is interrupted.(The Javadoc here says that it should raise a ClosedByInterruptException, but it doesn't.)

try (FileChannel channel = FileChannel.open(Paths.get(...), StandardOpenOption.CREATE,                                            StandardOpenOption.WRITE)) {    channel.transferFrom(Channels.newChannel(new URL(...).openStream()), 0, Long.MAX_VALUE);}

It also has the potential to perform much better than its java.io alternative.(However, it turns out that the implementation of Files.copy() may elect to delegate to this method instead of actually performing the copy by itself.)


Here's an example of a reusable JavaFX Service that lets you fetch a resource from the internet and save it to your local file-system, with automatic graceful termination if the operation takes too long.

  • The service task (spawned by createTask()) is the user of the file-channel API.
  • A separate ScheduledExecutorService is used to handle the time constraint.
  • Always stick to the good practices for extending Service.
  • If you choose to use such an high-level method, you won't be able to track down the progress of the task.
  • If the connection becomes unavailable, transferFrom() should eventually return without throwing an exception.

To start the service (may be done from any thread):

DownloadService downloadService = new DownloadService();downloadService.setRemoteResourceLocation(new URL("http://speedtest.ftp.otenet.gr/files/test1Gb.db"));downloadService.setPathToLocalResource(Paths.get("C:", "test1Gb.db"));downloadService.start();

and then to cancel it (otherwise it will be automatically cancelled after the time expires):

downloadService.cancel();

Note that the same service can be reused, just be sure to reset it before starting again:

downloadService.reset();

Here is the DownloadService class:

public class DownloadService extends Service<Void> {    private static final long TIME_BUDGET = 2; // In seconds    private final ScheduledExecutorService watchdogService =            Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {                private final ThreadFactory delegate = Executors.defaultThreadFactory();                @Override                public Thread newThread(Runnable r) {                    Thread thread = delegate.newThread(r);                    thread.setDaemon(true);                    return thread;                }            });    private Future<?> watchdogThread;    private final ObjectProperty<URL> remoteResourceLocation = new SimpleObjectProperty<>();    private final ObjectProperty<Path> pathToLocalResource = new SimpleObjectProperty<>();    public final URL getRemoteResourceLocation() {        return remoteResourceLocation.get();    }    public final void setRemoteResourceLocation(URL remoteResourceLocation) {        this.remoteResourceLocation.set(remoteResourceLocation);    }    public ObjectProperty<URL> remoteResourceLocationProperty() {        return remoteResourceLocation;    }    public final Path getPathToLocalResource() {        return pathToLocalResource.get();    }    public final void setPathToLocalResource(Path pathToLocalResource) {        this.pathToLocalResource.set(pathToLocalResource);    }    public ObjectProperty<Path> pathToLocalResourceProperty() {        return pathToLocalResource;    }    @Override    protected Task<Void> createTask() {        final Path pathToLocalResource = getPathToLocalResource();        final URL remoteResourceLocation = getRemoteResourceLocation();        if (pathToLocalResource == null) {            throw new IllegalStateException("pathToLocalResource property value is null");        }        if (remoteResourceLocation == null) {            throw new IllegalStateException("remoteResourceLocation property value is null");        }        return new Task<Void>() {            @Override            protected Void call() throws IOException {                try (FileChannel channel = FileChannel.open(pathToLocalResource, StandardOpenOption.CREATE,                                                            StandardOpenOption.WRITE)) {                    channel.transferFrom(Channels.newChannel(remoteResourceLocation.openStream()), 0, Long.MAX_VALUE);                }                return null;            }        };    }    @Override    protected void running() {        watchdogThread = watchdogService.schedule(() -> {            Platform.runLater(() -> cancel());        }, TIME_BUDGET, TimeUnit.SECONDS);    }    @Override    protected void succeeded() {        watchdogThread.cancel(false);    }    @Override    protected void cancelled() {        watchdogThread.cancel(false);    }    @Override    protected void failed() {        watchdogThread.cancel(false);    }}


There is one important aspect not covered by the other answers/comments; and that is a wrong assumption of yours:

What I want is it to fail immediately when no internet connection is there.

It is not that easy. The TCP stack/state machine is actually a pretty complicated thing; and depending on your context (OS type; TCP stack implementation, kernel parameters, ...), there can be situations where a network partition takes place and a sender doesn't notice for 15 or more minutes. Listen here for more details on that.

In other words: "just pulling the plug" is no way equal to "immediately breaking" your existing TCP connection. And just for the record: you don't need to plug cables manually to simulate network outages. In a reasonable test setup, tools like iptables aka firewalls can do that for you.


You seem to need an Asynchronous/Cancellable HTTP GET which can be tough.

The problem is that if read stalls waiting for more data (cable is pulled) it won't quit until either the socket dies or new data comes in.

There are a few path you could follow, tinkering with socket factories to set a good timeout, using http client with timeouts and others.

I would have a look at Apache Http Components which has non blocking HTTP based on java NIO Sockets.