GeekBand第八週筆記

一、線程是什麼
線程,有時被稱爲輕量級進程,是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針,寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。
一個線程可以創建和撤銷另一個線程,同一進程的多個線程之間可以併發執行。由於線程之間的相互制約,致使線程在運行中呈現出間斷性。

線程也有就緒,阻塞和運行三種基本狀態。

  • 就緒狀態就是指線程具備運行的所有條件,邏輯上可以運行,在等待處理機;

  • 運行狀態是指線程佔有處理機正在運行;

  • 阻塞狀態是指線程在等待一個事件(如某個信號量),邏輯上不可執行。每一個程序都 至少有一個線程,若程序只有一個線程,那就是程序本身。
    這裏寫圖片描述

    線程屬性

1.輕型實體
線程中的實體基本上不擁有系統資源,只是有一點必不可少,能保證獨立運行的資源。
線程的實體包括:程序,數據, TCB。線程是動態概念,它的動態性由線程控制塊TCB(Thread Control Block)
TCB包括: a,線程狀態 b,當線程不運行時,被保存的現場資源 c,一組執行堆棧 d,存放每個線程的局部變量主存區
e, 訪問同一個進程中的主存和其它資源。
用於指示被執行指令序列的程序計數器,保留局部變量,少數狀態參數和返回地址等的一組寄存器和堆棧。

2、 獨立調度和分派的基本單位
在多線程中OS,線程是能獨立運行的基本單位,因而也是獨立調度和分派的基本單位。由於線程很輕,故線程的切換非常迅速且開銷小,在同一進程中。

3、可併發執行
在一個進程中的多個線程之間,可以併發執行,甚至允許一個進程中所有線程都能併發執行。同樣,不同進程中的線程也能併發執行,充分利用和發揮了處理機與外圍設備並行工作的能力。

4.共享進程資源
在同一進程中的各個線程,都可以共享該進程所擁有的資源,這表現:所有線程都具有相同的地址空間(進程的地址空間),這意味着,線程可以訪問該地址空間的每一個虛地址。此外,還可以訪問進程所擁有的已打開文件,定時器,信號量機等,由於同一個進程內線程共享內存和文件,所以線程之間互相通信不必調用內核。

二、多線程是什麼?
多線程中,通常是一個進程中包括多個線程,每個線程都是作爲利用CPU的基本單位,是花費最小開銷的實體。

三、爲什麼要使用多線程?
效率更快,耗時操作不妨礙主線程進行其他任務,多項任務並行。

無論何時啓動APP,所有的組件都會運行在一個單獨的線程中(默認的)——叫做主線程。這個線程主要用於處理UI的操作併爲視圖組件和小部件分發事件等,因此主線程也被稱作UI線程。

如果你在UI線程中運行一個耗時操作,那麼UI就會被鎖住,直到這個耗時操作結束。對於用戶體驗來說,這是非常糟糕的!這也就是爲什麼我們要理解Android上的多線程使用。

理解這些可以把一些複雜的工作移動到其它的線程中去執行。如果你在UI線程中運行一個耗時的任務,那麼很有可能會發生ANR(應用無響應),這樣用戶就會很快地結束掉你的APP。

四、多線程的原理
這裏寫圖片描述

這裏寫圖片描述
這裏寫圖片描述

五、Android中的多線程 。
 Android中的Main線程的事件處理不能太耗時,否則後續的事件無法在5秒內得到響應,就會彈出ANR對話框。所以就必須要使用多線程來處理耗時操作,避免出現卡頓和異常。
但是,Android是單線程模型,這意味着Android UI操作並不是線程安全的,所以UI操作必須在UI線程中執行。
所以如何溝通,就很重要。

當你新開線程去處理耗時任務,返回的結果如何在UI上更新:
在WorkerThread如何更新UI
Activity. runOnUIThread(Runnable);
View.post(Runnable)
View.postDelayed(Runnable)
Handler
代碼如下:

//        UI線程
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text_view);

new Thread(new Runnable() {
  @Override
  public void run() {
    // 第一種 activity的方法
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
        mTextView.setText("我在其他線程。。。。");
        }
    });
    //  第二種
    mTextView.post(new Runnable() {
        @Override
        public void run() {
            mTextView.setText("我在其他線程。。。。");
        }
    });
    //    第三種
    mTextView.postDelayed(new Runnable() {
        @Override
        public void run() {
            mTextView.setText("我在其他線程。。。。");
        }
     },1000);
    //   第四種
    new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                mTextView.setText("我在其他線程。。。。");
            }
        });
        }
  });


}

多線程使用方法:
1.AsyncTask<>,異步處理適合一次性的任務。因使用次數較多,就不詳述了。

2.Handler,靈活,但也不適合大數量任務。

 private DownloadHandler mHandler=new DownloadHandler(this);

private void loadImagesByThread(final String url,final int id){
    //通過Thread來new 出多個線程  
    new Thread(new Runnable(){  
          @Override  
          public void run() {  
                // TODO Auto-generated method stub  
               Log.e("當前線程:", ""+Thread.currentThread().getName());  
             Drawable drawable = null;  
                try {  
                   drawable = Drawable.createFromStream(new URL(url).openStream(), "image.gif");  
               } catch (MalformedURLException e) {  
                   // TODO Auto-generated catch block  
                  e.printStackTrace();  
               } catch (IOException e) {  
                   // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
              Message msg = mHandler.obtainMessage();  
               msg.what = 2012;  
               msg.arg1 = id;  
               msg.obj = drawable;  
               msg.sendToTarget();  

           }  

        }).start();  
    }

public static class DownloadHandler extends Handler{
        private WeakReference<MainActivity> mWeakReference;
        public DownloadHandler(MainActivity activity) {
            mWeakReference=new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
             MainActivity activity=mWeakReference.get();
            switch (msg.what){
                case 2012:
                    ((ImageView)activity.findViewById(msg.arg1))
                        .setImageDrawable((Drawable)msg.obj); 
                break;
            }
        }
    }

3、ExecutorServie線程池,適合處理大量線程。

通過Executors的靜態方法來創建,一般有三種:

1.單線程 :Executors.newSingleThreadExecutor();

2.固定數量線程 :Executors.newFixedThreadPool();

3.動態線程 :Executors.newCachedThreadPool();

4.定時線程:Executors.newScheduleThreadPool();

這裏我們用固定幾個線程來應用,使用方法是創建ExecutorService對象,然後執行submit(r)可以發起一個Runnable對象。用線程池來管理的好處是,可以保證系統穩定運行,適用與有大量線程,高工作量的情景下使用,假如要展示1000張圖片如果創建1000個線程去加載,保證系統會死掉。用線程池就可以避免這個問題,可以用幾個線程輪流執行,幾個一組,執行完的線程不直接回收而是等待下次執行,這樣對系統的開銷就可以減小不少。

 private ExecutorService service = Executors.newFixedThreadPool(5); 
 private void loadImagesByExecutors(final String url,final int id){  
       service.submit(new Runnable(){        
          @Override  
          public void run() {  
               // TODO Auto-generated method stub  
             Log.e("當前線程程:",""+Thread.currentThread().getName());  

             try {  
                 final Drawable drawable  = Drawable.createFromStream(new URL(url).openStream(), "image.gif");  
                mHandler.post(new Runnable(){  
                    @Override  
                    public void run() {//這將在主線程運行  
                          // TODO Auto-generated method stub  
                           ((ImageView)MainActivity.this.findViewById(id)).setImageDrawable(drawable);  
                        }  
                    });  

               } catch (MalformedURLException e) {  
                   // TODO Auto-generated catch block  
                   e.printStackTrace();  
               } catch (IOException e) {  
                    // TODO Auto-generated catch block  
                   e.printStackTrace();  
                }  

           }  

       });  

   }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章