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 "";
    }

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

查看所有标签

猜你喜欢:

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

Servlet与JSP核心编程

Servlet与JSP核心编程

[美]Marty Hall、Larry Brown、Yaakov Chalkin / 胡书敏 / 2009-6 / 68.00元

《Servlet与JSP核心编程(第2卷 第2版)》在第l卷的基础上,广泛涉及自定义标签库、过滤器、声明式安全、JSTL和Struts等主题,并沿袭深受读者喜爱的写作风格,通过完整、有效、资料丰富的程序来演绎目前最流行的技术和最佳实践。Java EE已经成为电子商务网站、动态网站和Web应用与服务开发的首选,作为这一平台的基础,servlet与JSP的重要性日益突出,并在极短的时间内得以迅速普及。......一起来看看 《Servlet与JSP核心编程》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具