Java守护线程的理解笔记(2)

但是如果伪“守护线程”发现了某个文件下载超时,就会调用downloadTread.interrupt()方法停止当前的下载线程并且重新new一个下载线程继续之前的进度下载。

在这个地方,我发现

Thread.interrupt()方法并不会立即停止当前线程,当前线程会继续运行十几秒的时间


我的解决方法是修改Tread里的一个私有变量shouldStop,在跨过耗时操作之后检查这个私有变量,如果被修改过那么就return掉当前线程。


现在,我们斗胆把这个伪“守护线程”编程真的守护线程,用setDaemon(true)在start()之前实现。


public static void main(String[] args) throws IOException {
  // TODO Auto-generated method stub
  downloadThread = new DownloadThread();
  downloadThread.start();
  AlxDemonThread demonThread = new AlxDemonThread();
  demonThread.setDaemon(true);
  demonThread.start();
 }然后把我们用于停止伪“守护线程”的计数器去掉


//if(completedFileCount == total_times)return;
然后重新执行这个程序

1、如果下载很顺畅没有任何一个文件超时,那么守护线程会随着下载线程的终止而终止

2、如果有一个文件下载超时了,守护线程会自动new线程,但是这个线程和守护线程跑了没一会就停了,守护线程退出。

得出如下几个结论

1、守护线程由主线程创建,守护主线程,同样也守护主线程创建的所有子线程。

2、主线程如果终止(包括crash),由主线程创建的子线程并不会终止,守护线程也不会终止。

3、守护线程创建的所有线程都是守护线程,当父守护线程守护的线程终止,父守护线程及其创建的子守护线程都会一起停止

第三条有点拗口,简单解释一下就是:当守护线程把下载超时的线程停止掉之后,这个下载线程并不会立即停掉,此时守护线程又创建了一个下载线程,而这个由守护线程创建的下载线程并不好用,它会莫名其妙的随着上个下载线程的终止而终止。原因就是这个新下载线程其实时候守护线程,守护主线程(其实就是守护父守护线程,也就间接守护旧的下载线程),所以没等下完就自动终止了。


那么看来通过简单粗暴的设置守护线程并不好用,那么我们根据“守护线程会守护创建它的线程”的原理,让下载线程创建一个线程守护它自己,当这个守护线程发现下载线程超时以后,通知主线程创建一个新的下载线程进行下载,同时也有一个新的守护线程守护它


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Random;

import javax.net.ssl.HttpsURLConnection;


public class CopyOfDownloadTest {

public static long total;
 public static long startTime;
 public static int alreadyTime = 0;
 public static final String url = "https://d25hz2nnwuc2tq.cloudfront.net/images/image/cache/data/2016/10/19/1476866804-800x450-1080x608.webp";
 public static final int total_times = 100;
 
 private static Random threadLock = new Random();//线程锁
 
 public static void main(String[] args) throws IOException, InterruptedException {
  // TODO Auto-generated method stub
  new DownloadThread().start();
 
   while (1<2) {
    synchronized (threadLock) {//让主线程持有线程锁
     threadLock.wait();//锁住主线程
    }
    System.out.println("主线程解锁,准备重新new下载线程");
    new DownloadThread().start();
   }
 
 }
 
 public static class DownloadThread extends Thread{
  public boolean shouldStop = false;//超时后终结次进程
  public void run() {
   AlxDemonThread demonThread = new AlxDemonThread(this);
   demonThread.setDaemon(true);
   demonThread.start();
   for(int i=alreadyTime;i<total_times;i++){
    if(shouldStop)return;
    try {
     long cost = downloadNow(url, i);
     if(shouldStop)return;
     System.out.println("第"+i+"次耗时"+cost);
     
    } catch (Exception e) {
     // TODO: handle exception
     if(shouldStop)return;
     System.out.println("下载失败");
     e.printStackTrace();
    }
    if(shouldStop)return;
    alreadyTime++;
    total += System.currentTimeMillis() - startTime;
    startTime = 0;
   }
   if(!shouldStop)System.out.println("总耗时=="+total);
  }
 }
 
 public static class AlxDemonThread extends Thread{
  private DownloadThread mDownloadThread = null;
  public AlxDemonThread(DownloadThread t) {
   // TODO Auto-generated constructor stub
   this.mDownloadThread = t;
  }
  @Override
  public void run() {
   // TODO Auto-generated method stub
   super.run();
   while (2>1) {
    try {
     Thread.sleep(1000);
//     System.out.println("守护线程还活着");
    } catch (InterruptedException e) {
    }
    if(alreadyTime == total_times)return;
    if(System.currentTimeMillis() - startTime > 30*1000){
     System.out.println("第"+alreadyTime+"超时了");
     mDownloadThread.shouldStop = true;
     mDownloadThread.interrupt();
     alreadyTime++;
     total += 30*1000;
     synchronized (threadLock) {
      threadLock.notify();
     }
     return;//停掉守护线程,防止再new一个子线程
    }
    //因为是守护线程,所以在下载线程结束后会自动停止
   }
  }
 }
 
 public static long downloadNow(String strUrl,int times) throws IOException{
  startTime = System.currentTimeMillis();
  URL url = new URL(strUrl);
  HttpsURLConnection httpURLConnection = (HttpsURLConnection) url.openConnection();
        httpURLConnection.setDoInput(true);
        httpURLConnection.setUseCaches(false);
        httpURLConnection.setRequestMethod("GET");
        httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
        httpURLConnection.setRequestProperty("Charset", "UTF-8");
        httpURLConnection.setRequestProperty("Content-Type","multipart/form-data;boundary=" + "******");
        httpURLConnection.connect();
//        System.out.println("响应码是::"+httpURLConnection.getResponseCode());
        File pictureFile = new File("d:/speed/test"+times+".jpg");
        BufferedInputStream bis = new BufferedInputStream(httpURLConnection.getInputStream());
        FileOutputStream outputStream = new FileOutputStream(pictureFile);
        byte[] buffer = new byte[1024];
        int len = 0;
        BufferedOutputStream out = new BufferedOutputStream(outputStream);
        while ((len = bis.read(buffer)) != -1) {
         if(System.currentTimeMillis() - startTime > 30*1000)throw new RuntimeException("超时");
            out.write(buffer, 0, len);
        }
        out.flush();
        out.close();
        bis.close();
        return System.currentTimeMillis()-startTime;
 }

}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/1cec03be9ed6aa754429e1e3dda850f7.html