我要做Android之要點總結

迎著風發表於2018-09-16

Q:開啟一個執行緒的方法有哪些?銷燬一個執行緒的方法呢?

  1. 直接使用Thread類。
  2. 使用Runnable和Thread。
  3. 使用Runnable和執行緒池。
  4. 使用AsyncTask。
  5. 使用HandlerThread。
  6. 使用IntentService。

直接使用Thread類開啟子執行緒

這是最簡單開啟子執行緒的方法,也是最本質的方法,其他開啟子執行緒的方法都是在此方法基礎上的擴充套件。

一,使用示例如下:

new Thread(){
    @Override
    public void run() {
        super.run();
    }
}.start();

使用Thread類開啟子執行緒一共分為三步:

  1. 建立Thread的子類物件。
  2. 重寫run方法。
  3. 呼叫start方法開啟子執行緒。
    此時就開啟了子執行緒,run方法執行在子執行緒中。

使用Runnable介面和Thread類開啟子執行緒

此種方法使用的是Thread類的有參構造建立執行緒物件。

先例項實現了 Runnable 介面的類,之後在例項化一個 Thread,把介面類作為引數傳遞進去。之後呼叫 start 方法即可開啟。

使用Runnable和執行緒池開啟子執行緒

執行緒池中維護的是執行緒,所以使用執行緒池開啟子執行緒本質還是使用的Thread類,因為用到的類和方法不同,所以單獨列了出來。
使用示例如下:

ExecutorService threadPool = Executors.newFixedThreadPool(5);
threadPool.submit(new Runnable() {
    @Override
    public void run() {

    }
});

使用AsyncTask開啟子執行緒

AsyncTask是一個類,裡面封裝了Thread和Handler,開啟了子執行緒,實現了執行緒間的通訊。

使用示例

new AsyncTask<String, Integer, Boolean>() {
    protected void onPreExecute() {
        super.onPreExecute();
    }

    protected Boolean doInBackground(String... params) {
        publishProgress(1);
        return null;
    }

    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
    }

}.execute("abc");

使用HandlerThread開啟子執行緒

HandlerThread是一個類,他繼承了Thread類,並重寫了run方法,在run方法中使用Looper建立了訊息佇列,此時就可以在這種Thread中直接使用Handler了。

一,使用示例

HandlerThread mHandlerThread = new HandlerThread("MyHandlerThread");;
mHandlerThread.start();//開啟子執行緒
 Handler mhandler = new Handler(mHandlerThread.getLooper()){
     @Override
     public void handleMessage(Message msg) {
         //這個方法執行在子執行緒,裡面可以做耗時的操作
     }
 };

 mhandler.sendEmptyMessage(10);

分析:由於mHandlerThread.getLooper()得到的是子執行緒中的looper物件,所以mhandler是子執行緒中的handler,所以handleMessage方法也執行在子執行緒。

使用intentService開啟子執行緒

IntentService這是一個特殊的服務,它是一個抽象類,繼承了Service。裡面封裝了HandlerThread和Handler,本質等效於在服務中開啟一個子執行緒。而且這個服務可以在子執行緒執行結束後自動關閉。

一,使用示例

  public static class MyIntentService extends IntentService{
        public MyIntentService(String name) {
            super(name);
        }

        @Override
        protected void onHandleIntent(Intent intent) {
            //這個方法執行在子執行緒,裡面可以做耗時的操作
        }
    }

分析:自定義一個類,繼承intentService,然後重寫onHandleIntent方法,這個方法執行在子執行緒。

Q:Thread的join()有什麼作用?

thread.Join把指定的執行緒加入到當前執行緒,可以將兩個交替執行的執行緒合併為順序執行的執行緒。比如線上程B中呼叫了執行緒A的Join()方法,直到執行緒A執行完畢後,才會繼續執行執行緒B。

t.join(); //使呼叫執行緒 t 在此之前執行完畢。
t.join(1000); //等待 t 執行緒,等待時間是1000毫秒

volatile和synchronized的區別

  1. volatile本質是在告訴jvm當前變數在暫存器(工作記憶體)中的值是不確定的,需要從主存中讀取; synchronized則是鎖定當前變數,只有當前執行緒可以訪問該變數,其他執行緒被阻塞住。
  2. volatile僅能使用在變數級別;synchronized則可以使用在變數、方法、和類級別的
  3. volatile僅能實現變數的修改可見性,不能保證原子性;而synchronized則可以保證變數的修改可見性和原子性
  4. volatile不會造成執行緒的阻塞;synchronized可能會造成執行緒的阻塞。
  5. volatile標記的變數不會被編譯器優化;synchronized標記的變數可以被編譯器優化

tips:volitate不是用來同步的,主要還是獲取最新資料

同步方法和同步方法塊鎖住的是誰?

1.同步方法:

即有synchronized (同步,美 [`sɪŋkrənaɪzd] ) 修飾符修飾的方法。

由於java的每個物件都有一個內建鎖,當用此關鍵字修飾方法時,內建鎖會保護整個方法。在呼叫給方法前,要獲取內建鎖,否則處於阻塞狀態。

例:public synchronized getMoney(){}

注:synchronized修飾靜態方法,如果呼叫該靜態方法,將鎖住整個類。

2.同步程式碼塊

即有synchronized修飾符修飾的語句塊,被該關鍵詞修飾的語句塊,將加上內建鎖。實現同步。

例:synchronized(Object o ){}

同步是高開銷的操作,因此儘量減少同步的內容。通常沒有必要同步整個方法,同步部分程式碼塊即可。

同步方法預設用this或者當前類class物件作為鎖。

同步程式碼塊可以選擇以什麼來加鎖,比同步方法要更顆粒化,我們可以選擇只同步會發生問題的部分程式碼而不是整個方法。

Q:sleep()和wait()的區別?

1、每個物件都有一個鎖來控制同步訪問,Synchronized關鍵字可以和物件的鎖互動,來實現同步方法或同步塊。sleep()方法正在執行的執行緒主動讓出CPU(然後CPU就可以去執行其他任務),在sleep指定時間後CPU再回到該執行緒繼續往下執行(注意:sleep方法只讓出了CPU,而並不會釋放同步資源鎖!!!);wait()方法則是指當前執行緒讓自己暫時退讓出同步資源鎖,以便其他正在等待該資源的執行緒得到該資源進而執行,只有呼叫了notify()方法,之前呼叫wait()的執行緒才會解除wait狀態,可以去參與競爭同步資源鎖,進而得到執行。(注意:notify的作用相當於叫醒睡著的人,而並不會給他分配任務,就是說notify只是讓之前呼叫wait的執行緒有權利重新參與執行緒的排程);

2、sleep()方法可以在任何地方使用;wait()方法則只能在同步方法或同步塊中使用;

3、sleep()是執行緒類(Thread)的方法,呼叫會暫停此執行緒指定的時間,但監控依然保持,不會釋放物件鎖,到時間自動恢復;wait()是Object的方法,呼叫會放棄物件鎖,進入等待佇列,待呼叫notify()/notifyAll()喚醒指定的執行緒或者所有執行緒,才會進入鎖池,不再次獲得物件鎖才會進入執行狀態;

public class MultiThread {
    private static class Thread1 implements Runnable{       
        @Override
        public void run() {
            //由於 Thread1和下面Thread2內部run方法要用同一物件作為監視器,如果用this則Thread1和Threa2的this不是同一物件
            //所以用MultiThread.class這個位元組碼物件,當前虛擬機器裡引用這個變數時指向的都是同一個物件
            synchronized(MultiThread.class){
                System.out.println("enter thread1 ...");
                System.out.println("thread1 is waiting");
                try{
                    //釋放鎖有兩種方式:(1)程式自然離開監視器的範圍,即離開synchronized關鍵字管轄的程式碼範圍
                    //(2)在synchronized關鍵字管轄的程式碼內部呼叫監視器物件的wait()方法。這裡使用wait方法
                    MultiThread.class.wait();
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("thread1 is going on ...");
                System.out.println("thread1 is being over!");
            }
        }
    }

    private static class Thread2 implements Runnable{
        @Override
        public void run() { 
            //notify方法並不釋放鎖,即使thread2呼叫了下面的sleep方法休息10ms,但thread1仍然不會執行
            //因為thread2沒有釋放鎖,所以Thread1得不到鎖而無法執行
            synchronized(MultiThread.class){
                System.out.println("enter thread2 ...");
                System.out.println("thread2 notify other thread can release wait status ...");
                MultiThread.class.notify();
                System.out.println("thread2 is sleeping ten millisecond ...");
                try{
                    Thread.sleep(10);
                }catch(InterruptedException e){
                    e.printStackTrace();
                }
                System.out.println("thread2 is going on ...");
                System.out.println("thread2 is being over!");
            }
        }       
    }


    public static void main(String[] args) {
        new Thread(new Thread1()).start();
        try{
            Thread.sleep(10);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        new Thread(new Thread2()).start();
    }

}

Q: 談談你對程式導向,物件導向,面向切面的理解

程式導向(Procedure Oriented)是一種以過程為中心的程式設計思想。這些都是以什麼正在發生為主要目標進行程式設計,不同於物件導向的是誰在受影響。與物件導向明顯的不同就是封裝、繼承、類。

物件導向程式設計(Object Oriented Programming,OOP,物件導向程式設計)是一種計算機程式設計架構。OOP 的一條基本原則是計算機程式是由單個能夠起到子程式作用的單元或物件組合而成。OOP 達到了軟體工程的三個主要目標:重用性、靈活性和擴充套件性。為了實現整體運算,每個物件都能夠接收資訊、處理資料和向其它物件傳送資訊。

面向切面程式設計(Aspect Oriented Programming(AOP)),是一個比較熱門的話題。AOP主要實現的目的是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。

切面,指的是專案模組中某些業務邏輯。面向切面程式設計通俗一點就是面向業務的一種程式設計思想(當然業務需要一定的共性),然後通過代理完成類的建立,極大程度的降低程式碼的重複,有效的提高了程式碼的重用率和開發效率。。。當然結合IOC(控制反轉),將物件直接注入到代理類中,通過代理完成呼叫方法,那就更完美了

切面是橫跨流程的,實現某個特定位置的功能,面向功能進行抽象。具體流程只需做引用即可,而不至於不同流程中冗餘很多類似程式碼。


相關文章