多线程的认识

2018-08-11  本文已影响0人  dev晴天
 一、 原理:
1 不是说多线程开的越多越快。(手机迅雷 建议3-4个)
2 还受服务器带宽的影响。
3 可以理解为更多的cpu资源给了你(司马光砸缸多砸了几个口)

二 、 分析 把服务器的文件资源等分 客户端 分别下载每一小快 一起进行
1 获得服务器文件大小

2 在客户端创建大小和服务器端一样的文件(提前申请好空间)

2.1 每个线程下载的开始结束位置 记录

3 开多个线程下载文件

4 知道每个线程什么时候下载完毕


三、补充:随机访问文件(RandomAccessFile类)
此类的事例支持对随机访问文件的读取写入

 1、构造函数:
RandomAccessFile(File file,String mode)

mode可以为:r rw rws(包含元数据) rwd

RandomAccessFile(String name,String mode)

2、 一些方法:
 read()
 write()
 setLength() 设置此文件的长度
 seek(long pos) 设置指针偏移量 (达到每个线程从自己的位置开始)



Demo:

package com.example.administrator.httpclientdemo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class MainActivity extends AppCompatActivity {

   // private static String PATH = "http://xiazai.sogou.com/comm/redir?softdown=1&u=0Gd8piB609380vCOL7GwJe7o9WVvkHDRKoqPuf-gGiXUWLXBAm9x94tIfhLGrwKWYNK-LbFKNWlpNfJyk0ESHL8iE21YxdYX&pcid=-3080605666447722537&filename=QQ_Setup.exe&w=1907&stamp=20171204";//要下载文件的路径

    private static String PATH="http://192.168.56.1/Demo/girls.jpg";
    private static int ThreadCount = 3;//假设开启三个线程
    private Button btnMutilDownload;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initUI();//初始化ui
    }

    private void initUI() {
        btnMutilDownload = (Button) findViewById(R.id.mutil_down_load);
        // 点击事件处理
        btnMutilDownload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 下载逻辑
                httpRequest();
            }
        });
    }

    private void httpRequest() {
        //开启线程处理耗时 逻辑
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    URL url = new URL(PATH);
                    connection = (HttpURLConnection) url.openConnection();

                    connection.setRequestMethod("GET");
                    int code = connection.getResponseCode();
                    if (code == 200) {
                        // 请求成功  进行多线程下载的操作(四个步骤)

                        // 1 获取服务器返回文件的大小
                        int length = connection.getContentLength();
                        Log.d("TAG", "文件大小(字节) :" + length);
                        // 2 在客户端创建大小和服务器端一样的文件(提前申请好空间)
                        RandomAccessFile rafAccessFile = new RandomAccessFile(getCacheDir()+"gril.jpg", "rw");
                        rafAccessFile.setLength(length);
                        //计算每个线程下载的大小
                        int blockSize = length / ThreadCount;

                        for (int i = 0; i < ThreadCount; i++) {
                            int startIndex = i * blockSize;
                            int endIndex = (i + 1) * blockSize - 1;
                            // 特殊情况 最后一个线程
                            if (i == ThreadCount - 1) {
                                endIndex = length - 1;
                            }
                            //  3 开启线程去服务器下载文件 循环三次 三个线程
                                 new DownLoadThread(startIndex,endIndex,i).start();
                        }
                    }


                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    // 定义线程去服务器现在文件
    class DownLoadThread extends Thread {
        // 通过构造方法吧每个线程 下载的开始结束位置传进来
        private int startIndex;
        private int endIndex;
        private int ThreadId;

        public DownLoadThread(int startIndex, int endIndex, int ThreadId) {
            this.startIndex = startIndex;
            this.endIndex = endIndex;
            this.ThreadId = ThreadId;
        }

        @Override
        public void run() {
            //去服务器下载文件的逻辑
            HttpURLConnection connection = null;
            try {
                URL url = new URL(PATH);
                connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(5000);
                connection.setRequestMethod("GET");
                //  4 设置一个请求头Range(告诉服务器每个线程下载的开始结束位置)固定写法
                connection.setRequestProperty("Range","bytes="+startIndex+"-"+endIndex);
//设置分段下载的头信息。  Range:做分段数据请求用的
                int code = connection.getResponseCode();
               // 5 获得状态码
                if (code == 206) {
                    RandomAccessFile raf = new RandomAccessFile(getCacheDir()+"gril.jpg", "rw");
                    raf.seek(startIndex);
                    InputStream in = connection.getInputStream();
                //把数据写到文件中
                    int len=-1;
                    byte []buff = new byte[1024];
                    while((len=in.read())!=-1){
                        raf.write(buff,0,len);
                    }
                    raf.close();
                    Log.d("Tag", "下载完毕"+ThreadId);
                }
            } catch (Exception e) {
                e.prin tStackTrace();
            }
        }

    }
}





上一篇 下一篇

猜你喜欢

热点阅读