第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開(kāi)發(fā)者教程

Android 入門(mén)教程

菜單類(lèi)控件
菜單:Menu
并發(fā)編程
多線程

多線程

多線程可以讓你同時(shí)異步執(zhí)行多種任務(wù),是各種編程語(yǔ)言里很重要的一個(gè)概念。合理的采用多線程可以讓你的 App 擁有更好的運(yùn)行性能,但是如果使用不當(dāng)可能會(huì)讓你的程序非常混亂,出現(xiàn)很多令人費(fèi)解且難以定位的問(wèn)題。

1. 多線程初探

當(dāng)用戶打開(kāi)一個(gè) App 時(shí),Android 系統(tǒng)會(huì)創(chuàng)建一個(gè) Linux 進(jìn)程,同時(shí)在進(jìn)程中創(chuàng)建一個(gè)執(zhí)行線程,我們稱(chēng)之為“主線程”,因?yàn)?Andfoid 規(guī)定只能在主線程更新 UI,所以又叫“UI線程”。
系統(tǒng)在創(chuàng)建主線程的時(shí)候幫我們創(chuàng)建好了一套消息處理機(jī)制,包含了第 38 節(jié)提到的 Handler、Looper、MessageQueue 等模塊,主線程就利用這一套消息機(jī)制來(lái)實(shí)現(xiàn) Actvity、Fragment 的生命周期回調(diào)以及和其他 App 之間的通信。所有需要在 UI 線程執(zhí)行的任務(wù)都要首先被 push 到任務(wù)隊(duì)列中,然后等待主線程 Looper 來(lái)輪詢(xún)。如果我們將所有的任務(wù)都放到主線程的任務(wù)隊(duì)列,那么可能需要等很久才能執(zhí)行到,所以一個(gè)比較好的選擇就是將耗時(shí)任務(wù)單獨(dú)放到一個(gè)子線程中,這樣就可以獨(dú)享一個(gè) MessageQuene,并且不再占用主線程的資源。

2. 多線程注意事項(xiàng)

  • Android 規(guī)定刷新 UI 的操作必須在主線程執(zhí)行;
  • 網(wǎng)絡(luò)請(qǐng)求、數(shù)據(jù)庫(kù)或者文件 I / O 等都屬于耗時(shí)操作,非常容易導(dǎo)致主線程的阻塞造成 App 卡頓;
  • 由于主線程的 Looper 是按順序輪詢(xún) MessageQueue 的,所以主線程的所有任務(wù)都是同步執(zhí)行。這樣如果有耗時(shí)操作那么會(huì)阻塞主線程,后面的任務(wù)都需要等待耗時(shí)操作的執(zhí)行;
  • 除了 I / O 操作外,開(kāi)發(fā)人員需要自行評(píng)估任務(wù)的耗時(shí)情況,合理采用多線程避免主線程的阻塞;
  • Android 提供了多種創(chuàng)建和管理線程的方法,當(dāng)然如果有高并發(fā)的場(chǎng)景還有一些第三方庫(kù)可以使用,但是系統(tǒng)的線程、線程池可以應(yīng)對(duì)大部分常見(jiàn)場(chǎng)景。

接下來(lái)我們來(lái)看看具體怎么使用 Android 多線程。

3. 線程的使用方法

Java 虛擬機(jī)支持多線程并發(fā)編程,并發(fā)意味著同時(shí)執(zhí)行多個(gè)任務(wù)。在 Android 中常見(jiàn)的多線程常見(jiàn)就是在子線程執(zhí)行耗時(shí)操作,然后將結(jié)果通過(guò)線程間通信傳遞給主線程,主線程僅僅拿到結(jié)果進(jìn)行 UI 的刷新。

3.1 線程的創(chuàng)建

我們有兩種方式進(jìn)行線程的創(chuàng)建

  1. 繼承Thread實(shí)現(xiàn)一個(gè)線程類(lèi):
class TestThread extends Thread {
    @Override
    public void run() {
        Log.d("Threading", "繼承 Thread 的線程:"+Thread.currentThread().getName());
    }
}
  1. 實(shí)現(xiàn)Runnable接口
class TestRunnable implements Runnable {
    @Override
    public void run() {
        Log.d("Runable", "實(shí)現(xiàn) Runable 的線程>"+Thread.currentThread().getName());
    }
}

無(wú)論是哪種方式,都需要在類(lèi)中實(shí)現(xiàn)一個(gè)無(wú)參的run()方法,然后將線程的實(shí)際執(zhí)行任務(wù)放在run()方法中,在要用多線程的類(lèi)中需要?jiǎng)?chuàng)建出一個(gè)Runnable接口實(shí)例。

3.2 啟動(dòng)進(jìn)程

對(duì)于第一種創(chuàng)建方式,直接創(chuàng)建 TestThread 實(shí)例調(diào)用start()即可:

new TestThread().start()

而對(duì)于第二種方式,在創(chuàng)建 Thread 的同時(shí)傳入 Runnable 接口實(shí)例,然后調(diào)用start()

new Thread(new TestRunnable()).start()

調(diào)用了 Thread 對(duì)象的 start()之后,run()方法就會(huì)在我們的子線程中執(zhí)行了。

3.3 線程生命周期

和 Activity 一樣,Thread 在執(zhí)行過(guò)程中也有自己的生命周期,一共有 5 種狀態(tài):

  • **New:**剛創(chuàng)建好,還未執(zhí)行
  • **Runnable:**已經(jīng)調(diào)用了start(),等待 CPU 分配時(shí)間片
  • **Running:**正在運(yùn)行
  • **Blocked:**由于某些原因(等待、睡眠、CPU暫時(shí)回收資源等)線程進(jìn)入阻塞
  • **Dead:**線程任務(wù)執(zhí)行結(jié)束,或者主動(dòng)關(guān)閉

各個(gè)生命周期的切換如下圖:

thread

4. 多線程示例

本節(jié)創(chuàng)建兩個(gè)耗時(shí)子線程,在線程的開(kāi)始和結(jié)束分別打上日志,然后觀察兩個(gè)線程任務(wù)是同時(shí)執(zhí)行,還是需要等待其中一個(gè)線程的耗時(shí)任務(wù)執(zhí)行結(jié)束才能執(zhí)行第二個(gè)。
MainActivity 代碼很簡(jiǎn)單,在里面創(chuàng)建兩個(gè)線程,為了方便演示我們用“繼承自 Thread”和“實(shí)現(xiàn) Runnable”兩種方式來(lái)創(chuàng)建兩個(gè)線程:


package com.emercy.myapplication;

import android.app.Activity;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import androidx.annotation.Nullable;

import java.io.IOException;
import java.util.Random;

import static android.Manifest.permission.RECORD_AUDIO;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;

public class MainActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        new Thread() {
            @Override
            public void run() {
                Log.d("ThreadTest", "Thread1 start");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.d("ThreadTest", "Thread1 end");

            }
        }.start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("ThreadTest", "Thread2 start");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.d("ThreadTest", "Thread2 end");
            }
        }).start();
    }

    private void task() {
        for (int i = 0; i < 10; i++) {
            Log.d("Thread", Thread.currentThread().getName() + " 當(dāng)前i = " + i);
        }
    }
}

在兩個(gè)線程中通過(guò)sleep()來(lái)模擬 500 毫秒的耗時(shí)任務(wù),在任務(wù)的開(kāi)始和結(jié)束都打上日志,觀察結(jié)果如下:

圖片描述

可以看到首先會(huì)同時(shí)開(kāi)啟兩個(gè)子線程,然后分別同時(shí)執(zhí)行 500 毫秒的任務(wù),在執(zhí)行結(jié)束打上結(jié)束的 Log,可以證明兩個(gè) Thread 是同時(shí)執(zhí)行的。

5. 小結(jié)

本節(jié)學(xué)習(xí)了一個(gè)能讓你的 App 并發(fā)高效執(zhí)行任務(wù)的方式,多線程可以幫助你提升 App 的整體性能,但用之不當(dāng)可能會(huì)造成一定的資源浪費(fèi),所以一定要謹(jǐn)記本節(jié)所提到的注意事項(xiàng)。然后按照步驟去創(chuàng)建、運(yùn)行子線程,了解線程執(zhí)行的生命周期,讓程序更好的為用戶服務(wù)。