关于文件读写,线程超时终止问题

在对网络文件下载进行读写操作时,有时候会因为网络问题导致 “Connection reset” 异常以及有时会在一半的时候卡住,针对这个两种情况需要重新去下载,第一种异常比较好判断,可以直接拿错误信息即可判断,第二种情况想到的办法就是利用线程去解决,给下载单独开启一个子线程,并且给该子线程设定一个超时时间,当超过改时间时,则取消下载,中断该子线程!

在这里通过实现Callable接口类来设置超时任务:

package com.java.mytest;

import com.csvreader.CsvReader;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;

import java.io.*;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @Author win7
 * @Date 12/1/16 2:45 PM
 */
public class TestDownloadFile {
    private static String tempUrl = "http://xxxx/test.txt";
    private static String filePath;

    public static void main(String[] args) {
        String suffixName = tempUrl.substring(tempUrl.lastIndexOf("/") + 1, tempUrl.length());
        int timeout = 20; //秒.
        int num = 1;
        Boolean flag = null;
        while (true) {
            ExecutorService executor = Executors.newSingleThreadExecutor();
            Boolean result = false;
            DownloadFile downloadFile = new DownloadFile(suffixName, num);
            Future<Boolean> future = executor.submit(downloadFile);// 将任务提交到线程池中
            try {
                future.get(timeout, TimeUnit.SECONDS);// 设定在20秒的时间内完成
            } catch (InterruptedException e) {
                filePath = null;
                System.out.println("线程中断出错--------"+num);
            } catch (ExecutionException e) {
                filePath = null;
                System.out.println("线程服务出错--------"+num);
            } catch (TimeoutException e) {// 超时异常
                filePath = "Connection reset";
                System.out.println("线程服务超时--------"+num);
            } finally {
				//关闭此下载任务
                downloadFile.setIsStop(true);
                flag = future.cancel(true);// 中断执行此任务的线程
                System.out.println("线程服务关闭--------"+num);
                System.out.println("result is " + result);
				System.out.println("删除结果:"  + flag);
                executor.shutdownNow();//关闭ExecutorService,阻止等待任务启动并试图停止当前正在执行的任务
				//超过3次终止整个任务
                if (num >= 3){
                    break;
                }
            }
            if (StringUtils.isBlank(filePath)){
                System.out.println("download file is error!");
                break;
            }else {
                if ("Connection reset".equalsIgnoreCase(filePath)){
                    System.out.println("============Connection reset continue==========="+num);
                    num++;
                    continue;
                }else {
                    File file = new File(filePath);
                    if (file.exists()){
                        System.out.println("============SUCCESS==========="+num);
                        break;
                    }else {
                        System.out.println("============"+filePath+" continue==========="+num);
                        continue;
                    }
                }
            }
        }
    }


    static class DownloadFile implements Callable<Boolean> {
        private  String fileName;
        private int num;
        //是否关闭此下载任务
        private boolean isStop = false;

        public DownloadFile(String suffixName, int num) {
            this.fileName = suffixName;
            this.num = num;
        }

        /**
         * 将文件下载到本地
         */
        @Override
        public Boolean call(){
            filePath = "F:/" + fileName;
            URL url = null;
            URLConnection conn = null;
            try {
                url = new URL(tempUrl);
                conn = url.openConnection();
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (null == url || null == conn){
                filePath = null;
                return false;
            }
            try (
                    //try语句结束后自动关闭资源
                    InputStream inputStream = conn.getInputStream();
                    FileOutputStream outputStream = new FileOutputStream(filePath)
            ) {
                byte[] buffer = new byte[1204];
                int length;
                while ((length = inputStream.read(buffer)) != -1) {
                    if (isStop){
                        break;
                    }
                    outputStream.write(buffer, 0, length);
                }
            }catch (Exception e){
                filePath = e.getMessage();
                e.printStackTrace();
            }finally {
                File file = new File(filePath);
                if (file.exists()){
                    return true;
                }
                return false;
            }
        }

        public void setIsStop(boolean isStop) {
            this.isStop = isStop;
        }
    }
}
记录下上面代码遇到的坑:

如果任务超时了,从而执行了future.cancel(true)以及executor.shutdownNow()此时这个线程就应该终结,但是实际上由于用到了IO读写操作,并且是阻塞式的,所以这个线程并没有终止而是继续的存在的,要知道jvm只有在所有(非守护)线程推出后才会退出,所以此时的jvm并没有因为方法执行完毕而退出。

解决办法:

1、是在读写的时候加上一个是否停止的标识

2、将阻塞式的IO读写操作换成不阻塞的NIO读写操作(此方法没去测试,待下次有时间在测)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值