외부 스레드에서 실행중인 Java Files.copy ()를 강제 종료합니다.


Answers

다른 답변 / 설명에서 다루지 않는 한 가지 중요한 측면이 있습니다. 그것은 당신의 잘못된 가정입니다.

내가 원하는 것은 인터넷 연결이 없을 때 즉시 실패하는 것입니다.

그렇게 쉽지는 않습니다. TCP 스택 / 상태 머신은 실제로 매우 복잡합니다. 컨텍스트 (OS 유형, TCP 스택 구현, 커널 매개 변수 등)에 따라 네트워크 파티션이 발생하고 발신자가 15 이상을 알지 못하는 상황이 발생할 수 있습니다. 이에 대한 자세한 내용은 here 를 참조하십시오.

다른 말로하면 : "플러그를 뽑는 것"은 기존의 TCP 연결을 "즉시 깨는"것과 동일하지 않습니다. 그리고 단지 기록을 위해 : 네트워크 중단을 시뮬레이션하기 위해 수동으로 케이블을 연결할 필요가 없습니다. 합리적인 테스트 환경에서 iptables 와 같은 도구는 방화벽을 대신 사용할 수 있습니다.

Question

자바 8 에서 Files.copy ()를 취소하는 방법은 다음과 같습니다 .

그러나 이제는 ExtendedCopyOption.INTERRUPTIBLE 이 개인이기 때문에 작동하지 않습니다.

기본적으로 특정 URL 에서 파일을 다운로드하고 Files.copy() 사용하여 로컬 파일 시스템에 저장해야합니다. 현재 진행 상황을 ProgressBar 에 표시해야하기 때문에 JavaFX 서비스를 사용하고 있습니다.

그러나 작업이 너무 오래 걸리는 경우 Files.copy() 실행하는 스레드를 차단하는 방법을 모르겠습니다. Thread.stop() 은 적어도 원하지 않습니다. 심지어 Thread.interrupt() 실패합니다.

또한 인터넷 연결이 끊어지면 정상적으로 종료되도록 작업을 원합니다.

인터넷 연결을 사용할 수없는 경우를 테스트하려면 이더넷 케이블을 제거하고 3 초 후에 다시 연결합니다. 불행히도, Files.copy() 는 이더넷 케이블을 다시 넣었을 때만 반환됩니다. 즉시 실패 할 수 있습니다.

보시다시피, 내부적으로 Files.copy() 가 루프를 실행하고있어 스레드가 종료하지 못하게합니다.

Tester (OBS Studio exe 다운로드) :

/**
 * @author GOXR3PLUS
 *
 */
public class TestDownloader extends Application {

    /**
     * @param args
     */
    public static void main(String[] args) {
    launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
    // Block From exiting
    Platform.setImplicitExit(false);

    // Try to download the File from URL
    new DownloadService().startDownload(
        "https://github.com/jp9000/obs-studio/releases/download/17.0.2/OBS-Studio-17.0.2-Small-Installer.exe",
        System.getProperty("user.home") + File.separator + "Desktop" + File.separator + "OBS-Studio-17.0.2-Small-Installer.exe");

    }

}

DownloadService :

FileChannel @sillyfly 주석을 사용 하고 File.copy 제거하면 Thread.interrupt() 를 호출 할 때만 작동하는 것으로 보이지만 인터넷을 사용할 수없는 경우 종료되지 않습니다.

import java.io.File;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.file.StandardOpenOption;
import java.util.logging.Level;
import java.util.logging.Logger;

import javafx.concurrent.Service;
import javafx.concurrent.Task;

/**
 * JavaFX Service which is Capable of Downloading Files from the Internet to the
 * LocalHost
 * 
 * @author GOXR3PLUS
 *
 */
public class DownloadService extends Service<Boolean> {

    // -----
    private long totalBytes;
    private boolean succeeded = false;
    private volatile boolean stopThread;

    // CopyThread
    private Thread copyThread = null;

    // ----
    private String urlString;
    private String destination;

    /**
     * The logger of the class
     */
    private static final Logger LOGGER = Logger.getLogger(DownloadService.class.getName());

    /**
     * Constructor
     */
    public DownloadService() {
    setOnFailed(f -> System.out.println("Failed with value: " + super.getValue()+" , Copy Thread is Alive? "+copyThread.isAlive()));
    setOnSucceeded(s -> System.out.println("Succeeded with value: " + super.getValue()+" , Copy Thread is Alive? "+copyThread.isAlive()));
    setOnCancelled(c -> System.out.println("Succeeded with value: " + super.getValue()+" , Copy Thread is Alive? "+copyThread.isAlive()));
    }

    /**
     * Start the Download Service
     * 
     * @param urlString
     *            The source File URL
     * @param destination
     *            The destination File
     */
    public void startDownload(String urlString, String destination) {
    if (!super.isRunning()) {
        this.urlString = urlString;
        this.destination = destination;
        totalBytes = 0;
        restart();
    }
    }

    @Override
    protected Task<Boolean> createTask() {
    return new Task<Boolean>() {
        @Override
        protected Boolean call() throws Exception {

        // Succeeded boolean
        succeeded = true;

        // URL and LocalFile
        URL urlFile = new URL(java.net.URLDecoder.decode(urlString, "UTF-8"));
        File destinationFile = new File(destination);

        try {
            // Open the connection and get totalBytes
            URLConnection connection = urlFile.openConnection();
            totalBytes = Long.parseLong(connection.getHeaderField("Content-Length"));





            // --------------------- Copy the File to External Thread-----------
            copyThread = new Thread(() -> {

            // Start File Copy
            try (FileChannel zip = FileChannel.open(destinationFile.toPath(), StandardOpenOption.CREATE,
                StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)) {

                zip.transferFrom(Channels.newChannel(connection.getInputStream()), 0, Long.MAX_VALUE);


                // Files.copy(dl.openStream(), fl.toPath(),StandardCopyOption.REPLACE_EXISTING)

            } catch (Exception ex) {
                stopThread = true;
                LOGGER.log(Level.WARNING, "DownloadService failed", ex);
            }

            System.out.println("Copy Thread exited...");
            });
            // Set to Daemon
            copyThread.setDaemon(true);
            // Start the Thread
            copyThread.start();
            // -------------------- End of Copy the File to External Thread-------






            // ---------------------------Check the %100 Progress--------------------
            long outPutFileLength;
            long previousLength = 0;
            int failCounter = 0;
            // While Loop
            while ((outPutFileLength = destinationFile.length()) < totalBytes && !stopThread) {

            // Check the previous length
            if (previousLength != outPutFileLength) {
                previousLength = outPutFileLength;
                failCounter = 0;
            } else
                ++failCounter;

            // 2 Seconds passed without response
            if (failCounter == 40 || stopThread)
                break;

            // Update Progress
            super.updateProgress((outPutFileLength * 100) / totalBytes, 100);
            System.out.println("Current Bytes:" + outPutFileLength + " ,|, TotalBytes:" + totalBytes
                + " ,|, Current Progress: " + (outPutFileLength * 100) / totalBytes + " %");

            // Sleep
            try {
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                LOGGER.log(Level.WARNING, "", ex);
            }
            }

            // 2 Seconds passed without response
            if (failCounter == 40)
            succeeded = false;
           // --------------------------End of Check the %100 Progress--------------------

        } catch (Exception ex) {
            succeeded = false;
            // Stop the External Thread which is updating the %100
            // progress
            stopThread = true;
            LOGGER.log(Level.WARNING, "DownloadService failed", ex);
        }







        //----------------------Finally------------------------------

        System.out.println("Trying to interrupt[shoot with an assault rifle] the copy Thread");

        // ---FORCE STOP COPY FILES
        if (copyThread != null && copyThread.isAlive()) {
            copyThread.interrupt();
            System.out.println("Done an interrupt to the copy Thread");

            // Run a Looping checking if the copyThread has stopped...
            while (copyThread.isAlive()) {
            System.out.println("Copy Thread is still Alive,refusing to die.");
            Thread.sleep(50);
            }
        }

        System.out.println("Download Service exited:[Value=" + succeeded + "] Copy Thread is Alive? "
            + (copyThread == null ? "" : copyThread.isAlive()));

        //---------------------- End of Finally------------------------------




        return succeeded;
        }

    };
    }

}

흥미로운 질문 :

1> java.lang.Thread.interrupt ()는 무엇을합니까?




Links