




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】多線程下載的基本原理和用法
剛學(xué)了下多線程的下載,可能是初次接觸的原因吧,理解起來(lái)覺(jué)得稍微有點(diǎn)難。所以想寫(xiě)一篇博客來(lái)記錄下,加深自己理解的同時(shí),也希望能夠幫到一些剛接觸的小伙伴。由于涉及到網(wǎng)絡(luò)的傳輸,那么就會(huì)涉及到http協(xié)議。建議在讀本文之前您對(duì)http協(xié)議有一定的了解。
線程可以通俗的理解為下載的通道,一個(gè)線程就是文件下載的一個(gè)通道,多線程就是同時(shí)打開(kāi)了多個(gè)通道對(duì)文件進(jìn)行下載。當(dāng)服務(wù)器提供下載服務(wù)時(shí),用戶之間共享帶寬,在優(yōu)先級(jí)相同的情況下,總服務(wù)器會(huì)對(duì)總下載線程進(jìn)行平均分配。我們平時(shí)用的迅雷下載就是多線程下載。
線程可以通俗的理解為下載的通道,一個(gè)線程就是文件下載的一個(gè)通道,多線程就是同時(shí)打開(kāi)了多個(gè)通道對(duì)文件進(jìn)行下載。當(dāng)服務(wù)器提供下載服務(wù)時(shí),用戶之間共享帶寬,在優(yōu)先級(jí)相同的情況下,總服務(wù)器會(huì)對(duì)總下載線程進(jìn)行平均分配。我們平時(shí)用的迅雷下載就是多線程下載。1:獲取目標(biāo)文件的大?。╰otalSize)
按照常識(shí),我們?cè)谙螺d一個(gè)文件之前,通常情況下是要知道該文件的大小,這樣才好在本地留好足量的空間來(lái)存儲(chǔ),免得出現(xiàn)還未下載完,存儲(chǔ)空間就爆了的情況。為了方便代碼的演示,本文在本地tomcat服務(wù)器的webapps/ROOT目錄下新建一個(gè)test.txt的文件,里面存儲(chǔ)了0123456789這10字節(jié)的數(shù)據(jù)。
按照常識(shí),我們?cè)谙螺d一個(gè)文件之前,通常情況下是要知道該文件的大小,這樣才好在本地留好足量的空間來(lái)存儲(chǔ),免得出現(xiàn)還未下載完,存儲(chǔ)空間就爆了的情況。為了方便代碼的演示,本文在本地tomcat服務(wù)器的webapps/ROOT目錄下新建一個(gè)test.txt的文件,里面存儲(chǔ)了0123456789這10字節(jié)的數(shù)據(jù)。2:確定要開(kāi)啟幾個(gè)線程(threadCount)
需要的文件在服務(wù)器上,那我們要開(kāi)通幾個(gè)通道去下載呢?一般情況下這是由CPU去決定的,但是CPU開(kāi)啟線程的數(shù)目也是有限的,不是想開(kāi)幾個(gè)線程就開(kāi)幾個(gè)線程。所開(kāi)線程的最大數(shù)量=(CPU核數(shù)+1),例如你的CPU核數(shù)為4,那么電腦最多可以開(kāi)啟5條線程。為了方便代碼演示,本文的threadCount=3
需要的文件在服務(wù)器上,那我們要開(kāi)通幾個(gè)通道去下載呢?一般情況下這是由CPU去決定的,但是CPU開(kāi)啟線程的數(shù)目也是有限的,不是想開(kāi)幾個(gè)線程就開(kāi)幾個(gè)線程。所開(kāi)線程的最大數(shù)量=(CPU核數(shù)+1),例如你的CPU核數(shù)為4,那么電腦最多可以開(kāi)啟5條線程。為了方便代碼演示,本文的threadCount=33:計(jì)算平均每個(gè)線程需要下載多少個(gè)字節(jié)的數(shù)據(jù)(blockSize)
理想情況下多線程下載是按照平均分配原則的,即:?jiǎn)尉€程下載的字節(jié)數(shù)等于文件總大小除以開(kāi)啟的線程總條數(shù),當(dāng)不能整除時(shí),則最后開(kāi)啟的線程將剩余的字節(jié)一起下載。例如:本文中的totalSize=10,threadCount=3,則前兩個(gè)開(kāi)啟的線程下載3KB的數(shù)據(jù),第三個(gè)開(kāi)啟的線程需要下載(3+1)KB的數(shù)據(jù)。
理想情況下多線程下載是按照平均分配原則的,即:?jiǎn)尉€程下載的字節(jié)數(shù)等于文件總大小除以開(kāi)啟的線程總條數(shù),當(dāng)不能整除時(shí),則最后開(kāi)啟的線程將剩余的字節(jié)一起下載。例如:本文中的totalSize=10,threadCount=3,則前兩個(gè)開(kāi)啟的線程下載3KB的數(shù)據(jù),第三個(gè)開(kāi)啟的線程需要下載(3+1)KB的數(shù)據(jù)。4:計(jì)算各個(gè)線程要下載的字節(jié)范圍。
平時(shí)我們做項(xiàng)目講究分工明確,同理多線程下載也需要明確各個(gè)下載的字節(jié)范圍,這樣才能將文件高效、快速、準(zhǔn)確的下載下來(lái)。即在下載過(guò)程中,各個(gè)線程都要明確自己的開(kāi)始索引(startIndex)和結(jié)束索引(endIndex)。
平時(shí)我們做項(xiàng)目講究分工明確,同理多線程下載也需要明確各個(gè)下載的字節(jié)范圍,這樣才能將文件高效、快速、準(zhǔn)確的下載下來(lái)。即在下載過(guò)程中,各個(gè)線程都要明確自己的開(kāi)始索引(startIndex)和結(jié)束索引(endIndex)。從上圖我們可以總結(jié)出一個(gè)公式:startIndex=threadId乘以blockSize;endIndex=(threadId+1)乘以blockSize-1;如果是最后一條線程,那么結(jié)束索引為:endIndex=totalSize-1;5:使用for循環(huán)開(kāi)啟3個(gè)子線程//每次循環(huán)啟動(dòng)一條線程下載
for(intthreadId=0;threadId<3;threadId++){
/**
*計(jì)算各個(gè)線程要下載的字節(jié)范圍
*/
//開(kāi)始索引
intstartIndex=threadId*blockSize;
//結(jié)束索引
intendIndex=(threadId+1)*blockSize-1;
//如果是最后一條線程(因?yàn)樽詈笠粭l線程可能會(huì)長(zhǎng)一點(diǎn))
if(threadId==(threadCount-1)){
endIndex=totalSize-1;
}
/**
*啟動(dòng)子線程下載
*/
newDownloadThread(threadId,startIndex,endIndex).start();
}6:獲取各個(gè)線程的目標(biāo)文件的開(kāi)始索引和結(jié)束索引的范圍。
告訴服務(wù)器,只要目標(biāo)段的數(shù)據(jù),這樣就需要通過(guò)Http協(xié)議的請(qǐng)求頭去設(shè)置(range:bytes=0-499)
告訴服務(wù)器,只要目標(biāo)段的數(shù)據(jù),這樣就需要通過(guò)Http協(xié)議的請(qǐng)求頭去設(shè)置(range:bytes=0-499)connection.setRequestProperty("range","bytes="+startIndex+"-"+endIndex);7:使用RandomAccessFile隨機(jī)文件訪問(wèn)類。創(chuàng)建一個(gè)RandomAccessFile對(duì)象,將返回的字節(jié)流寫(xiě)到文件指定的范圍
此處有個(gè)注意事項(xiàng):讓RandomAccessFile對(duì)象寫(xiě)字節(jié)流之前,需要移動(dòng)RandomAccessFile對(duì)象到指定的位置開(kāi)始寫(xiě)。
此處有個(gè)注意事項(xiàng):讓RandomAccessFile對(duì)象寫(xiě)字節(jié)流之前,需要移動(dòng)RandomAccessFile對(duì)象到指定的位置開(kāi)始寫(xiě)。raf.seek(startIndex);以上就是多線程下載的大致步驟。代碼如下:packagecom.example;
importjava.io.InputStream;
importjava.io.RandomAccessFile;
import.HttpURLConnection;
import.URL;
publicclassDownloadTest{
privatestaticfinalStringpath="http://localhost:8080/test.txt";
publicstaticvoidmain(String[]args)throwsException{
/**
*1.獲取目標(biāo)文件的大小
*/
inttotalSize=newURL(path).openConnection().getContentLength();
System.out.println("目標(biāo)文件的總大小為:"+totalSize+"B");
/**
*2.確定開(kāi)啟幾個(gè)線程
*開(kāi)啟線程的總數(shù)=CPU核數(shù)+1;例如:CPU核數(shù)為4,則最多可開(kāi)啟5條線程
*/
intavailableProcessors=Runtime.getRuntime().availableProcessors();
System.out.println("CPU核數(shù)是:"+availableProcessors);
intthreadCount=3;
/**
*3.計(jì)算每個(gè)線程要下載多少個(gè)字節(jié)
*/
intblockSize=totalSize/threadCount;
//每次循環(huán)啟動(dòng)一條線程下載
for(intthreadId=0;threadId<3;threadId++){
/**
*4.計(jì)算各個(gè)線程要下載的字節(jié)范圍
*/
//開(kāi)始索引
intstartIndex=threadId*blockSize;
//結(jié)束索引
intendIndex=(threadId+1)*blockSize-1;
//如果是最后一條線程(因?yàn)樽詈笠粭l線程可能會(huì)長(zhǎng)一點(diǎn))
if(threadId==(threadCount-1)){
endIndex=totalSize-1;
}
/**
*5.啟動(dòng)子線程下載
*/
newDownloadThread(threadId,startIndex,endIndex).start();
}
}
//下載的線程類
privatestaticclassDownloadThreadextendsThread{
privateintthreadId;
privateintstartIndex;
privateintendIndex;
publicDownloadThread(intthreadId,intstartIndex,intendIndex){
super();
this.threadId=threadId;
this.startIndex=startIndex;
this.endIndex=endIndex;
}
@Override
publicvoidrun(){
System.out.println("第"+threadId+"條線程,下載索引:"+startIndex+"~"+endIndex);
//每條線程要去×××器拿取目標(biāo)段的數(shù)據(jù)
try{
//創(chuàng)建一個(gè)URL對(duì)象
URLurl=newURL(path);
//開(kāi)啟網(wǎng)絡(luò)連接
HttpURLConnectionconnection=(HttpURLConnection)url.openConnection();
//添加配置
connection.setConnectTimeout(5000);
/**
*6.獲取目標(biāo)文件的[startIndex,endIndex]范圍
*/
//告訴服務(wù)器,只要目標(biāo)段的數(shù)據(jù),這樣就需要通過(guò)Http協(xié)議的請(qǐng)求頭去設(shè)置(range:bytes=0-499)
connection.setRequestProperty("range","bytes="+startIndex+"-"+endIndex);
connection.connect();
//獲取響應(yīng)碼,注意,由于服務(wù)器返回的是文件的一部分,因此響應(yīng)碼不是200,而是206
intresponseCode=connection.getResponseCode();
//判斷響應(yīng)碼的值是否為206
if(responseCode==206){
//拿到目標(biāo)段的數(shù)據(jù)
InputStreamis=connection.getInputStream();
/**
*7:創(chuàng)建一個(gè)RandomAccessFile對(duì)象,將返回的字節(jié)流寫(xiě)到文件指定的范圍
*/
//獲取文件的信息
StringfileName=getFileName(path);
//rw:表示創(chuàng)建的文件即可讀也可寫(xiě)。
RandomAccessFileraf=newRandomAccessFile("d:/"+fileName,"rw");
/**
*注意:讓raf寫(xiě)字節(jié)流之前,需要移動(dòng)raf到指定的位置開(kāi)始寫(xiě)
*/
raf.seek(startIndex);
//將字節(jié)流數(shù)據(jù)寫(xiě)到file文件中
byte[]buffer=newbyte[1024];
intlen=0;
while((len=is.read(buffer))!=-1){
raf.write(buffer,0,len);
}
//關(guān)閉資源
is.clos
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 水閣楊梅山施工方案
- 廣告門(mén)頭施工方案
- 石材粘接施工方案
- 火燒板臺(tái)階施工方案
- 橋梁亮化工程施工方案
- 室外管道安裝施工方案
- TSJNX 002-2024 西安市水平衡測(cè)試報(bào)告編制規(guī)范
- 二零二五年度物流信息承運(yùn)合同模板
- 二零二五年度承攬合同中增值稅稅率變動(dòng)應(yīng)對(duì)策略
- 二零二五年度交通事故人傷賠償公益援助協(xié)議
- 小學(xué)生漫畫(huà)獨(dú)立學(xué)習(xí)力(全3冊(cè))
- 2022年機(jī)械設(shè)計(jì)基礎(chǔ)(第四版)全冊(cè)教案
- 高一年級(jí)上期班主任教育敘事
- 軟件工程導(dǎo)論(第六版)電子教案(第1-13章)
- 廣東2017年07月自考10424資本運(yùn)營(yíng)與融資試題及答案
- 精神醫(yī)學(xué)案例習(xí)題集
- GB/T 35545-2017低聚木糖
- GB/T 16956-1997船用集裝箱綁扎件
- GB/T 10184-2015電站鍋爐性能試驗(yàn)規(guī)程
- 2023年出入境邊防檢查題庫(kù)
- 小兒推拿學(xué)理論知識(shí)考核試題及答案
評(píng)論
0/150
提交評(píng)論