Android 总结2-线程

栏目: Android · 发布时间: 5年前

内容简介:ActivityThread 为 Android 主线程ThreadLocal 存储器,做到只有该线程自己能够访问。就是多个线程访问同一份数据,每个线程得到数据不一致。理解为一个 Map,它的 set 和 get 方法都有一个“隐形的” key,那就是当前的线程对象,所以它才可以为每个线程保存一个数据副本。IntentService 继承自Service,并且是一个抽象类。IntentService封装了Handler和HandlerThread,所以这个Handler是子线程中的,适合执行耗时后台任务。
  • 1.继承Thread
  • 2.实现Runnable
  • 3.Handler
  • 4.AnsyTask
  • 5.HandlerThread

ActivityThread 为 Android 主线程

2.AnsyTask

  • AsyncTask 最好在主线程中初始化。因为AsyncTask需要Handler来将执行结果回调切回主线程,Handler 中Looper.getMainLooper()。所以异步线程初始化也没关系

  • excute()最好在主线程中初始化。并且一个AsyncTask只能执行一次excute(),否则会报错。其内部有一个枚举类型的Status用于维护执行状态:PENDING、RUNNING、FINISHED。默认情况下是PENDING,表示可以执行,当调用execute方法之后,会检查其状态是否是PENDING,如果不是的话就会抛出异常。

  • 经过测试。AsyncTask 可以在子线程初始化 和 excute() 可以在子线程中进执行

  • Android 1.6之前为串行,之后改为并行,3.0由改为串行。

    • execute()串行执行 —>调用executeOnExecutor(),并传入一个sDefaultExecutor(串行线程池)

    • sDefaultExecutor是SerialExecutor的一个实例,而且它是个静态变量。也就是说,一个进程里面所有AsyncTask对象都共享同一个SerialExecutor对象。

    • asyncTestThread.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,””); 并行执行最大5个线程。(固定线程数量的线程池)

      AsyncTask.THREAD_POOL_EXECUTOR。也可以使用自己的线程池。

  • AsyncTask 中有两个线程池,SerialExecutor 和用于任务排队的线程池。

3.HandlerThread

  • 继承自Thread,是一个子线程中创建了Handler
  • HandlerThread 中run是无限循环,不需要时可以挂起,
  • 在getLooper 中会try catch,避免looper为空
  • 获取子线程创建Handler
//创建HandlerThread实例
HandlerThread mHandlerThread = new HandlerThread("handler_thread");
//开始运行线程
mHandlerThread.start();
//获取HandlerThread线程中的Looper实例
Looper loop = mHandlerThread.getLooper();
//创建Handler与该线程绑定。
mSubThreadHandler = new Handler(loop){
public void handleMessage(Message msg) {}
}

4.ThreadLocal

ThreadLocal 存储器,做到只有该线程自己能够访问。就是多个线程访问同一份数据,每个线程得到数据不一致。理解为一个 Map,它的 set 和 get 方法都有一个“隐形的” key,那就是当前的线程对象,所以它才可以为每个线程保存一个数据副本。

5.IntentService

IntentService 继承自Service,并且是一个抽象类。IntentService封装了Handler和HandlerThread,所以这个Handler是子线程中的,适合执行耗时后台任务。

stopSelf(int startId) 会等任务执行结束后停掉服务,而stopSelf()会立即结束。

6.Handler

  • 主线程创建
    • Handler uiHandler = new Handler();
    • Handler uiHandler = new Handler(Looper.getMainLooper());
  • 创建子线程Handler
    • Handler threadHandler = new Handler(mHandlerThread.getLooper());获取子线程Looper
  • 原理,根据Looper找到关联的消息队列
    Android 总结2-线程

子线程创建Handler,需要先进行 Looper.prepare()

new Thread(){   
       @Override    
       public void run() {        
           Looper.prepare();  //获取当前线程的Looper,并prepare();
           Handler handler = new Handler() {           
               @Override          
               public void handleMessage(Message msg) {                
                   Toast.makeText(MainActivity.this, "handler msg", Toast.LENGTH_SHORT).show();            
               }        
           };        
           handler.sendEmptyMessage(0);   
           Looper.loop();  //looper开始处理消息。
       }
}.start();

7.继承Thread

TestThread testThread = new TestThread();
testThread.start();


class TestThread extends Thread {
    @Override
    public void run() {
        super.run();
    }
}

8.Runnable

TestRunnable run = new TestRunnable();
Thread tt = new Thread(run);
tt.start();

class TestRunnable implements Runnable{
    @Override
    public void run() {
    }
}

9. AsyncTask 示例

AsyncTestThread asyncTestThread = new AsyncTestThread();
asyncTestThread.execute();// 串行
asyncTestThread.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"");//并行

class AsyncTestThread extends AsyncTask<String, String, String> {
       // 1作用:执行 线程任务前的操作
       @Override
       protected void onPreExecute() {
           Log.e("jfson", "pre 0");
           super.onPreExecute();
       }

       // 2作用:接收输入参数、执行任务中的耗时操作、返回 线程任务执行的结果
       @Override
       protected String doInBackground(String... strings) {
           for (int i = 0; i < 100; i++) {
               try {
                   Thread.sleep(100);
                   //进度条每次更新10%,执行中创建新线程处理onProgressUpdate()
                   publishProgress(String.valueOf(i));
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
           Log.e("jfson", "doInBackground finish :");
           return "下载完成!";
       }

       // 3作用:在主线程 显示线程任务执行的进度
       @Override
       protected void onProgressUpdate(String... values) {
           Log.e("jfson", "onProgressUpdate :" + values[0]);
           super.onProgressUpdate(values);
       }

       // 4作用:接收线程任务执行结果..UI线程
       @Override
       protected void onPostExecute(String s) {
           Log.e("jfson", "onPostExecute :" + s);
           super.onPostExecute(s);
       }

       // 5任务执行完成、UI线程
       @Override
       protected void onCancelled() {
           Log.e("jfson", "onCancelled :");
           super.onCancelled();
       }
  }

10.多线程的实现 or api 实现

线程池API分析

  • 1.创建
    • a.ThreadPoolExecutor.newFixedThreadPool();创建线程数量固定的线程池
    • b.ThreadPoolExecutor.newSingleThreadExecutor();线程数固定为1的线程池
    • c.ThreadPoolExecutor.newCachedThreadPool();会缓存的线程池,线程数量可以从0到Integer.MAX_VALUE,超时时间为1分钟。线程池用起来的效果是:如果有空闲线程,会复用线程;如果没有空闲线程,会新建线程;如果线程空闲超过1分钟,将会被回收。
    • d. ThreadPoolExecutor.newScheduledThreadPool();将会创建一个可定时执行任务的线程池。
  • 2.BlockingQueue
    • newCachedThreadPool的线程上限几乎等同于无限,但系统资源是有限的,任务的处理速度总有可能比不上任务的提交速度。因此,可以为ThreadPoolExecutor提供一个阻塞队列来保存因线程不足而等待的Runnable任务,这就是BlockingQueue。
  • 3.SynchronousQueue
    • newCachedThreadPool使用的SynchronousQueue十分有趣,看名称是个队列,但它却不能存储元素。要将一个任务放进队列,必须有另一个线程去接收这个任务,一个进就有一个出,队列不会存储任何东西。因此,SynchronousQueue是一种移交机制,不能算是队列。newCachedThreadPool生成的是一个没有上限的线程池,理论上提交多少任务都可以,使用SynchronousQueue作为等待队列正合适。
  • 4.饱和策略
    • 当有界的等待队列满了之后,就需要用到饱和策略去处理,ThreadPoolExecutor的饱和策略通过传入RejectedExecutionHandler来实现。如果没有为构造函数传入,将会使用默认的defaultHandler。
    • a.AbortPolicy是默认的实现,直接抛出一个RejectedExecutionException异常,让调用者自己处理。
    • b.DiscardPolicy的rejectedExecution直接是空方法,什么也不干。如果队列满了,后续的任务都抛弃掉。
    • c.DiscardOldestPolicy会将等待队列里最旧的任务踢走,让新任务得以执行。
    • d.CallerRunsPolicy,它既不抛弃新任务,也不抛弃旧任务,而是直接在当前线程运行这个任务。当前线程一般就是主线程啊,让主线程运行任务,说不定就阻塞了。如果不是想清楚了整套方案,还是少用这种策略为妙。
  • 5.线程池的执行
    • 线程池是由Worker类负责执行任务,Worker继承了AbstractQueuedSynchronizer,引出了 Java 并发框架的核心AQS。
    • worker在线程池里的四种可能(Worker在构造函数里采用ThreadFactory创建Thread,在run方法里调用了runWorker,看来是真正执行任务的地方。) Android 总结2-线程
  • 6.线程池的关闭
    • shutdown:不能再提交任务,已经提交的任务可继续运行;
    • shutdownNow:不能再提交任务,已经提交但未执行的任务不能运行,在运行的任务可继续运行,但会被中断,返回已经提交但未执行的任务。
  • 7.Join、wait、notify、notifyAll、run()和start()
    • Join()将改线程优先级提升,执行完后才可以执行其他线程。底层是利用wait()实现,主线程先获得了t对象的锁,t执行完成后,主线程继续执行,其他线程开始执行。
    • 在 Java 中,可以通过配合调用 Object 对象的 wait() 方法和 notify()方法或 notifyAll() 方法来实现线程间的通信。在线程中调用 wait() 方法,将阻塞等待其他线程的通知(其他线程调用 notify() 方法或 notifyAll() 方法),在线程中调用 notify() 方法或 notifyAll() 方法,将通知其他线程从 wait() 方法处返回。
    • run()和start()
      • 1) start()
        用start方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码。通过调用Thread类的start()方法来启动一个线程,这时此线程处于就绪(可运行)状态,并没有运行,一旦得到cpu时间片,就开始执行run()方法,这里方法 run()称为线程体,它包含了要执行的这个线程的内容,Run方法运行结束,此线程随即终止。
      • 2)run()方法只是类的一个普通方法而已,如果直接调用Run方法,程序中依然只有主线程这一个线程,其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的。总结:调用start方法方可启动线程,而run方法只是thread的一个普通方法调用,还是在主线程里执行。这两个方法应该都比较熟悉,把需要并行处理的代码放在run()方法中,start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void。

10.手写一个线程池

  • 主要用 private BlockingQueue taskQueue=new LinkedBlockingDeque (); 存储任务Runnable。
  • //线程工作组,WorkerThread[] workThreads;存储初始化的线程
  • taskQueue.take();// 获取并移除第一个元素 没有则扔进
 public void execute(Runnable task) {    
        synchronized (taskQueue) {    
            taskQueue.add(task);    
            taskQueue.notifyAll();  //当调用execute()方法的时候,执行notiry(),只会唤醒线程池中的一个线程,注意与notoryAll()的区别    
        }    
    }  
    
/*内部类 即一个线程池对象*/  
    private class WorkThread extends Thread{  
        //该工作线程是否有效,用来接收该工作线程  
        private boolean isRunnable=true;  
        /*  
         * 关键所在,如果任务队列不空,则求出任务执行,若任务队列为空,则等待  
        */  
        @Override  
        public void run() {  
            //接收队列当中的任务对象 任务对象Runnable类型  
            Runnable r=null;  
            while(isRunnable){  
                //队列同步机制  
                synchronized(taskQueue){  
                    while(isRunnable && taskQueue.isEmpty()){//队列为空  
                        try {  
                            taskQueue.wait(20);  
                        } catch (InterruptedException e) {  
                            // TODO Auto-generated catch block  
                            e.printStackTrace();  
                        }  
                    }  
                    if(!taskQueue.isEmpty()){  
                        try {  
                            r=taskQueue.take();// 获取并移除第一个元素  
                        } catch (InterruptedException e) {  
                            // TODO Auto-generated catch block  
                            e.printStackTrace();  
                        }  
                    }  
                    if(r!=null){  
                        r.run();//执行任务  
                    }  
                    executeTaskNumber++;  
                    r=null;  
                }  
            }  
        }  
        public void stopWorker(){  
            isRunnable=false;  
        }  
    }

HttpURLConnection

public static String get(IRequest request) {
        InputStream inputStream = null;
        HttpURLConnection httpURLConnection = null;
        try {
            URL url = new URL(buildGetUrl(request.getBaseUrl(), request.getParam(), request.getEncrypt()));
            openUrlConnection(url,httpURLConnection);
            normalSetting(httpURLConnection, Method.GET, request.getHeaders());
            if (httpURLConnection == null) {
                return null;
            }
            int responseCode = httpURLConnection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                inputStream = httpURLConnection.getInputStream();
                String contentEncoding = httpURLConnection.getContentEncoding();
                InputStream stream = null;
                try {
                    stream = wrapStream(contentEncoding, inputStream);
                    String data = convertStreamToString(stream);
                    return data;
                } catch (IOException e) {
                    return "";
                } finally {
                    closeQuietly(stream);
                }

            }
            return null;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入浅出程序设计(中文版)

深入浅出程序设计(中文版)

Paul Barry、David Griffiths / 蒋雁翔、童健 / 东南大学出版社 / 2012-1 / 98.00元

《深入浅出程序设计(中文版)》介绍了编写计算机程序的核心概念:变量、判断、循环、函数与对象——无论运用哪种编程语言,都能在动态且多用途的python语言中使用具体示例和练习来运用并巩固这些概念。学习基本的工具来开始编写你感兴趣的程序,而不是其他人认为你应该使用的通用软件,并对软件能做什么(不能做什么)有一个更好的了解。当你完成这些,你就拥有了必要的基础去使用任何一种你需要或想要学习的语言或软件项目......一起来看看 《深入浅出程序设计(中文版)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具