junit多线程有坑!!!

    xiaoxiao2021-03-25  60

    junit多线程测试有坑!!!

    今天在测试自己写的一个多线程下载器的时候,在最后用junit单元测试的时候一直得不到想要的结果,程序进行到一半就突然中止了。 下面先贴出下载器的代码

    package com.coderising.multiThreadDownloader; import java.io.File; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class MultiThreadDownloader { private String downloadAdress = "http://img.xmpig.com/forum/201610/20/201816z4zvp3zov8vtpp5g.jpg"; private String storePathString = "f:/"; private int threadNum = 4; public MultiThreadDownloader() { } public MultiThreadDownloader(String downloadAdress, String storePathString, int threadNum) { this.downloadAdress = downloadAdress; this.storePathString = storePathString; this.threadNum = threadNum; } public void download() { try { URL url = new URL(downloadAdress); HttpURLConnection httpURLConnection = (HttpURLConnection) url .openConnection(); httpURLConnection.setRequestMethod("GET"); httpURLConnection.setReadTimeout(10000); int code=httpURLConnection.getResponseCode(); if (code== 200) { int len = httpURLConnection.getContentLength(); RandomAccessFile rFile = new RandomAccessFile(new File(storePathString, DownloadThread.getFileName(url)), "rw"); rFile.setLength(len); int threadSize = len / threadNum; for (int id = 0; id < threadNum; id++) { int startIndex = id * threadSize; int endIndex = (id + 1) * threadSize - 1; if (id == threadNum - 1) { endIndex = len - 1; } Thread thread = new DownloadThread(id, downloadAdress, storePathString, startIndex, endIndex); thread.start(); } //Thread.sleep(3000); System.out.println("download success"); } }catch (Exception e) { e.printStackTrace(); } } }

    上面代码是主要根据地址获得资源的大小,把资源划分为不同的块儿,分别启用下面的线程,下载各自的范围块儿

    package com.coderising.multiThreadDownloader; import java.io.File; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; public class DownloadThread extends Thread { private int id; private String downloadPath; private String storePath; private int startIndex; private int endIndex; public DownloadThread(int id, String downloadPath,String storePath, int startIndex, int endIndex) { this.downloadPath = downloadPath; this.id = id; this.storePath=storePath; this.startIndex = startIndex; this.endIndex = endIndex; } @Override public void run() { // TODO Auto-generated method stub try { System.out.println("Thread " + id + "开始下载:"); URL url = new URL(downloadPath); File tmpFile = new File(storePath, getFileName(url) + id); RandomAccessFile rFile = null; if (tmpFile.exists()) { rFile = new RandomAccessFile(tmpFile, "rwd"); String start = rFile.readLine(); this.startIndex = Integer.parseInt(start); } else { rFile = new RandomAccessFile(tmpFile, "rwd"); } HttpURLConnection httpURLConnection = (HttpURLConnection) url .openConnection(); httpURLConnection.setRequestMethod("GET"); httpURLConnection.setConnectTimeout(10000); httpURLConnection.setRequestProperty("Range", "bytes="+ startIndex + "-" + endIndex); int code=httpURLConnection.getResponseCode(); System.out.println("Thread "+id+" code: "+code); if ( code== 206) {//206表示部分资源获得成功 InputStream inputStream = httpURLConnection.getInputStream(); RandomAccessFile randomAccessFile = new RandomAccessFile(new File(storePath, getFileName(url)), "rw"); randomAccessFile.seek(startIndex); byte[] tmp = new byte[1024]; int length = -1; int total = 0; while ((length = inputStream.read(tmp)) > 0) { randomAccessFile.write(tmp, 0, length); total += length; rFile.seek(0); rFile.write((startIndex + total + "").getBytes("UTF-8")); } rFile.close(); inputStream.close(); randomAccessFile.close(); cleanTmp(tmpFile); System.out.println("thread "+id+"下载完成"); }else{ System.out.println("响应吗:"+code+"--不支持多线程下载"); } } catch (Exception e) { e.printStackTrace(); } } public static String getFileName(URL url) { String name = url.getFile(); name = name.substring(name.lastIndexOf("/") + 1); return name; } private synchronized void cleanTmp(File file){ file.delete(); } }

    下载器的逻辑并不复杂,junit测试就是new一个MultiThreadDownloader最后期望的对象,然后执行download()方法,结果就是在”F:/”下面得到所下载的图片,并且能够正确的显示,控制台应该显示:

    Thread 0开始下载: Thread 1开始下载: Thread 3开始下载: Thread 2开始下载: Thread 0 code: 206 Thread 3 code: 206 Thread 1 code: 206 Thread 2 code: 206 thread 2下载完成 thread 0下载完成 thread 3下载完成 thread 1下载完成 download success

    但是最后结果却显示

    Thread 0开始下载: download success Thread 1开始下载: Thread 2开始下载: Thread 3开始下载:

    图片当然也没有下载完成。我把自己的代码看了又看,小bug倒是有一些,但是并没有找到程序终止的原因,而且程序每次终止的结果都不一样。 最后想到是不是junit不太会玩儿,哪儿出错了,因此在MultiThreadDownloader类里面,用一个main方法进行测试,最后居然下载成功了。所以果然还是junit的锅。 最后经过查询,junit并不适合多线程,在junit的主线程运行完毕以后,会强行停止测试,并不会考虑到创建的子线程是否执行完毕,所以出现了上面程序莫名停止在不同的地方。 所以,如果你依旧想用junit测试多线程,需要额外的操作,来保证子线程的完成: 1.用Thread.sleep()强行停止主线程,等待子线程执行完毕,缺点就是等待多长时间,需要你主观去把握。 2.使用CountDownLatch类,每个子线程计数器减1,直到计数器减为0,然后结束主线程。 3.使用CyckicBarrier类,线程集等待预定数目到达一个barrier时,选择执行一个处理barrier的动作。

    转载请注明原文地址: https://ju.6miu.com/read-37560.html

    最新回复(0)