Android線程相關(guān)部分知識(shí)點(diǎn)

線程相關(guān)的,現(xiàn)在基本上都是核心,這個(gè)必須要會(huì)。

正文

有一個(gè)大的邏輯前提,就是計(jì)算機(jī)其實(shí)分為用戶層和系統(tǒng)層的,操作系統(tǒng)的主要作用是調(diào)度硬件資源,同時(shí)分配硬件資源。Android AOSP其實(shí)一個(gè)基于Linux的類(lèi)似于桌面應(yīng)用的東西,同時(shí)提供了豐富的API和服務(wù),幫助我們調(diào)用硬件相關(guān)及其處理硬件交互。而JAVA 的虛擬機(jī),他最終也是基于不同的操作系統(tǒng),調(diào)用不同的實(shí)現(xiàn),最后也調(diào)用到了系統(tǒng)上面去。所以,這一趴啦下來(lái),就是說(shuō),系統(tǒng)是核心。那么像創(chuàng)建線程,創(chuàng)建進(jìn)程這種底層的活,他其實(shí)就是調(diào)用到是系統(tǒng)的函數(shù)。扯遠(yuǎn)了。

JAVA程序的執(zhí)行是以進(jìn)程為單位,每個(gè)JAVA 程序至少包含一個(gè)進(jìn)程,main是函數(shù)的入口,他屬于主線程,并在該進(jìn)程中被執(zhí)行。

線程

在Android 中,JAVA 線程依舊是通過(guò)用POSIX線程(pthread)庫(kù)來(lái)創(chuàng)建線程。

volatile

用于確保多線程環(huán)境下的內(nèi)存可見(jiàn)性,當(dāng)一個(gè)變量被聲明為volatile的時(shí)候,他可以確保每個(gè)線程內(nèi)存中都使用最新的值。

  • 禁止指令重排,編譯器和處理器可能會(huì)對(duì)指令進(jìn)行重排,以提高執(zhí)行效率,但是多線程環(huán)境中,這可能導(dǎo)致數(shù)據(jù)不一致。確保了每次訪問(wèn)變量的順序都是一致的。
  • 保證內(nèi)存的可見(jiàn)性,當(dāng)一個(gè)線程修改了一個(gè)volatile 變量的時(shí)候,其他線程會(huì)立即看到這個(gè)變化,這是通過(guò)緩存一致性寫(xiě)一來(lái)實(shí)現(xiàn)的。
  • 但是不能保證原子性,也就是說(shuō),無(wú)法保證復(fù)合操作,如自增或自減。

synchronized

是一種內(nèi)置的同步機(jī)制,在多線程環(huán)境下保護(hù)共享資源的訪問(wèn),他用于確保同一時(shí)刻只有一個(gè)線程可以訪問(wèn)被synchronized 保護(hù)的代碼塊或方法。當(dāng)被聲明為synchronized時(shí)候,JAVA 會(huì)在方法內(nèi)部創(chuàng)建一個(gè)監(jiān)視器鎖,每個(gè)線程執(zhí)行該方法之前必須獲取這個(gè)鎖,如果一個(gè)線程已經(jīng)獲取到這個(gè)鎖,其他線程不能進(jìn)入這個(gè)方法,直到鎖被釋放,從而保護(hù)共享資源的訪問(wèn)。通過(guò)這種原理,也就是說(shuō),這個(gè)關(guān)鍵字可以保證內(nèi)存的可見(jiàn)性與數(shù)據(jù)的原子性。因?yàn)榇嬖诰€程阻塞的問(wèn)題,而volatile 可以保證數(shù)據(jù)的可見(jiàn)性。所以這兩者是可以互補(bǔ)的,但是不建議同時(shí)使用。

什么是死鎖

線程死鎖是指兩個(gè)或兩個(gè)以上的線程互相持有對(duì)方所需要的資源,由于synchronized的特性,一個(gè)線程持有一個(gè)資源,或者說(shuō)獲得一個(gè)鎖,在該線程釋放這個(gè)鎖之前,其他線程獲取不到這個(gè)鎖,就會(huì)一直等待下去。

atomic

在JAVA類(lèi)中,atomic 類(lèi)提供了一種實(shí)現(xiàn)原子操作的機(jī)制,確保在多線程環(huán)境下,對(duì)共享變量的操作是原子的,即不會(huì)被其他線程中斷。

atomic 類(lèi)的實(shí)現(xiàn)原理是通過(guò)CAS(compare and swap)指令實(shí)現(xiàn)的,CAS是一種基于硬件原語(yǔ)的操作,他可以在不使用鎖的情況下實(shí)現(xiàn)多線程間的數(shù)據(jù)同步。CAS指令包括3個(gè)操作數(shù),分別是需要更新的內(nèi)存位置,舊的預(yù)期值和新的值。CAS指令會(huì)先比較內(nèi)存位置的值是否等于舊的預(yù)期值,如果相對(duì)則將新的值寫(xiě)入到該內(nèi)存中,否則不進(jìn)行任何操作,CAS指令是一種樂(lè)觀鎖機(jī)制,他假設(shè)并發(fā)沖突 情況很少發(fā)生,因此不需要使用互斥鎖。

如果多個(gè)線程同時(shí)對(duì)一個(gè)atomic對(duì)象進(jìn)行操作,那么只有最先成功完成操作的線程會(huì)獲得成功結(jié)果,其他線程的操作都會(huì)被重試或忽略,所以需要避免發(fā)生沖突的情況。

ReentrantLock

是JAVA中的一個(gè)可重入鎖,他是一種比synchronized 關(guān)鍵字更靈活的線程同步機(jī)制,他允許一個(gè)線程多次獲取同一個(gè)鎖而不會(huì)產(chǎn)生死鎖。特點(diǎn):

  • 可重入性,允許多次獲取同一個(gè)鎖,而不會(huì)產(chǎn)生死鎖。
  • 公平性,可以配置為公平鎖和非公平鎖,公平鎖按照線程請(qǐng)求鎖的順序分配鎖,非公平鎖則沒(méi)有這個(gè)限制。
  • 中斷獲取,提供一個(gè)中斷獲取鎖的方法,可以在獲取鎖的過(guò)程中中斷。
  • tryLock,嘗試獲取鎖,如果被占用就返回false。
  • lockinterruptibly 方法,用于嘗試獲取鎖,如果被鎖,則等待鎖釋放,如果等待過(guò)程中線程被中斷,則拋出interruptedException。

需要手動(dòng)調(diào)用lock 和unlock 方法來(lái)獲取和釋放鎖,這就比synchronized 更加的靈活。實(shí)例代碼:

Lock  lock  =  new  ReentrantLock();

public  void  doSth()  {
    lock.lock()  ;
    try  {
      // 執(zhí)行某些操作
    }  finally  {
      lock.unlock();
    }
}

Condition

是object 類(lèi)同步方法之一,他用于在多線程環(huán)境中控制對(duì)象訪問(wèn),condition接口提供了一種機(jī)制,讓線程等待某個(gè)滿足條件或者通知其他線程某個(gè)條件已經(jīng)滿足。

Condition 接口通常與 Lock 接口一起使用。Lock 接口提供了一種更靈活的鎖機(jī)制,可以控制多個(gè)線程對(duì)同一個(gè)資源的訪問(wèn)順序。Condition 接口則提供了在特定 Lock 對(duì)象上等待和通知的條件機(jī)制。

使用 Condition 接口,可以調(diào)用 await() 方法讓當(dāng)前線程等待某個(gè)條件滿足,調(diào)用 signal() 方法通知等待在該 Condition 對(duì)象上的某個(gè)線程可以繼續(xù)執(zhí)行,調(diào)用 signalAll() 方法通知等待在該 Condition 對(duì)象上的所有線程可以繼續(xù)執(zhí)行。

下面是一個(gè)簡(jiǎn)單的示例代碼,展示了如何使用 Condition 接口:

import java.util.concurrent.locks.Condition;  
import java.util.concurrent.locks.Lock;  
import java.util.concurrent.locks.ReentrantLock;  
  
public class Example {  
    private Lock lock = new ReentrantLock();  
    private Condition condition = lock.newCondition();  
    private int count = 0;  
  
    public void increment() {  
        lock.lock();  
        try {  
            count++;  
            condition.signalAll(); // 通知所有等待的線程  
        } finally {  
            lock.unlock();  
        }  
    }  
  
    public void decrement() {  
        lock.lock();  
        try {  
            count--;  
            condition.await(); // 等待其他線程執(zhí)行 increment() 方法后繼續(xù)執(zhí)行  
        } catch (InterruptedException e) {  
            Thread.currentThread().interrupt();  
        } finally {  
            lock.unlock();  
        }  
    }  
}

Semaphore

Semaphore 是一個(gè)計(jì)數(shù)信號(hào)量,用于控制對(duì)共享資源的訪問(wèn)。它維護(hù)一個(gè)計(jì)數(shù)器,表示當(dāng)前可用的許可證數(shù)量。當(dāng)一個(gè)線程需要訪問(wèn)共享資源時(shí),它會(huì)嘗試獲取一個(gè)許可證,如果計(jì)數(shù)器大于零,則許可證被成功獲取,線程可以繼續(xù)執(zhí)行;如果計(jì)數(shù)器為零,則線程需要等待,直到其他線程釋放許可證。當(dāng)線程使用完共享資源后,它會(huì)釋放一個(gè)許可證,以便其他線程可以繼續(xù)訪問(wèn)。

Semaphore 的使用非常靈活,可以用于實(shí)現(xiàn)多種并發(fā)控制邏輯。例如,可以使用 Semaphore 來(lái)限制對(duì)某個(gè)共享資源的并發(fā)訪問(wèn)數(shù)量,以保證該資源在同一時(shí)刻只被一定數(shù)量的線程訪問(wèn)。也可以使用 Semaphore 來(lái)實(shí)現(xiàn)線程間的協(xié)作和同步,例如使用 Semaphore 來(lái)控制一個(gè)生產(chǎn)者線程和消費(fèi)者線程之間的數(shù)據(jù)流,保證生產(chǎn)者不會(huì)在所有消費(fèi)者都未準(zhǔn)備好接收數(shù)據(jù)的情況下生產(chǎn)數(shù)據(jù)。

在 Java 中,Semaphore 的實(shí)現(xiàn)類(lèi)是 java.util.concurrent.Semaphore。它提供了構(gòu)造函數(shù)和方法來(lái)設(shè)置初始許可證數(shù)量和獲取/釋放許可證。使用 Semaphore 需要對(duì)其進(jìn)行實(shí)例化,并調(diào)用其 acquire() 和 release() 方法來(lái)獲取和釋放許可證。

下面是一個(gè)簡(jiǎn)單的示例代碼,展示了如何使用 Semaphore 來(lái)限制對(duì)共享資源的并發(fā)訪問(wèn)數(shù)量:

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    private Semaphore semaphore = new Semaphore(3); // 限制并發(fā)訪問(wèn)數(shù)量為3

    public void doSomething() {
        try {
            semaphore.acquire(); // 獲取一個(gè)許可證,如果沒(méi)有可用則等待
            // 執(zhí)行需要訪問(wèn)共享資源的代碼
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release(); // 釋放一個(gè)許可證
        }
    }
}

在這個(gè)例子中,Semaphore 的初始許可證數(shù)量被設(shè)置為3,意味著最多有3個(gè)線程可以同時(shí)訪問(wèn)共享資源。當(dāng)一個(gè)線程調(diào)用 doSomething() 方法時(shí),它會(huì)嘗試獲取一個(gè)許可證,如果沒(méi)有可用則等待。當(dāng)線程執(zhí)行完需要訪問(wèn)共享資源的代碼后,它會(huì)釋放一個(gè)許可證,以便其他線程可以繼續(xù)訪問(wèn)。

CyclicBarrier

CyclicBarrier 是 Java 中的一個(gè)并發(fā)工具類(lèi),它可以用于實(shí)現(xiàn)多個(gè)線程之間的同步和協(xié)作。CyclicBarrier 允許一組線程互相等待,直到所有線程都到達(dá)一個(gè)公共屏障點(diǎn)(Barrier point),然后再一起繼續(xù)執(zhí)行。

CyclicBarrier 的特點(diǎn)是它可以重復(fù)使用,因此得名“循環(huán)”屏障。與 Semaphore 不同的是,CyclicBarrier 的計(jì)數(shù)器不會(huì)自動(dòng)增加,而是需要顯式地調(diào)用 reset() 方法來(lái)重置計(jì)數(shù)器。

CyclicBarrier 的使用非常靈活,可以用于實(shí)現(xiàn)多種并發(fā)控制邏輯。例如,可以使用 CyclicBarrier 來(lái)實(shí)現(xiàn)多個(gè)線程之間的同步,讓它們?cè)诠财琳宵c(diǎn)處進(jìn)行等待,然后再一起執(zhí)行后續(xù)的操作。也可以使用 CyclicBarrier 來(lái)實(shí)現(xiàn)分階段的任務(wù)執(zhí)行,每個(gè)階段由一組線程執(zhí)行,然后在所有階段都完成后一起進(jìn)行下一步操作。

在 Java 中,CyclicBarrier 的實(shí)現(xiàn)類(lèi)是 java.util.concurrent.CyclicBarrier。它提供了構(gòu)造函數(shù)和方法來(lái)設(shè)置線程數(shù)量和在屏障點(diǎn)處執(zhí)行的回調(diào)函數(shù)。使用 CyclicBarrier 需要對(duì)其進(jìn)行實(shí)例化,并調(diào)用 await() 方法來(lái)等待其他線程到達(dá)屏障點(diǎn)。

下面是一個(gè)簡(jiǎn)單的示例代碼,展示了如何使用 CyclicBarrier 來(lái)實(shí)現(xiàn)多個(gè)線程之間的同步:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    private CyclicBarrier barrier = new CyclicBarrier(3); // 設(shè)置線程數(shù)量為3

    public void doSomething() {
        try {
            barrier.await(); // 在公共屏障點(diǎn)處等待其他線程到達(dá)
            // 執(zhí)行需要同步的代碼
        } catch (InterruptedException | BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

在這個(gè)例子中,CyclicBarrier 的線程數(shù)量被設(shè)置為3,意味著只有當(dāng)3個(gè)線程都到達(dá)公共屏障點(diǎn)時(shí),才會(huì)一起繼續(xù)執(zhí)行。當(dāng)一個(gè)線程調(diào)用 doSomething() 方法時(shí),它會(huì)嘗試在公共屏障點(diǎn)處等待其他線程到達(dá)。當(dāng)所有線程都到達(dá)公共屏障點(diǎn)后,它們會(huì)一起繼續(xù)執(zhí)行需要同步的代碼。

CountDownLatch

CountDownLatch 是 Java 中的一個(gè)并發(fā)工具類(lèi),它允許一個(gè)或多個(gè)線程等待其他線程完成操作。CountDownLatch 的主要功能是提供一個(gè)計(jì)數(shù)器,用于統(tǒng)計(jì)需要等待的線程數(shù)量。當(dāng)計(jì)數(shù)器歸零時(shí),所有等待的線程才會(huì)繼續(xù)執(zhí)行。

CountDownLatch 的使用非常方便,可以用于實(shí)現(xiàn)多種并發(fā)控制邏輯。例如,在生產(chǎn)者-消費(fèi)者模型中,可以使用 CountDownLatch 來(lái)控制生產(chǎn)者和消費(fèi)者之間的同步。當(dāng)生產(chǎn)者生產(chǎn)完一定數(shù)量的數(shù)據(jù)后,可以調(diào)用 CountDownLatch 的 countDown() 方法減少計(jì)數(shù)器的值。消費(fèi)者在消費(fèi)數(shù)據(jù)之前需要先調(diào)用 CountDownLatch 的 await() 方法等待計(jì)數(shù)器歸零,然后再繼續(xù)執(zhí)行后續(xù)操作。

在 Java 中,CountDownLatch 的實(shí)現(xiàn)類(lèi)是 java.util.concurrent.CountDownLatch。它提供了構(gòu)造函數(shù)和方法來(lái)設(shè)置計(jì)數(shù)器的初始值和獲取當(dāng)前計(jì)數(shù)器的值。使用 CountDownLatch 需要對(duì)其進(jìn)行實(shí)例化,并調(diào)用 await() 方法來(lái)等待計(jì)數(shù)器歸零,或者調(diào)用 countDown() 方法來(lái)減少計(jì)數(shù)器的值。

下面是一個(gè)簡(jiǎn)單的示例代碼,展示了如何使用 CountDownLatch 來(lái)實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者之間的同步:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CountDownLatchExample {
    private static final int N = 10; // 生產(chǎn)者需要生產(chǎn)的數(shù)量
    private CountDownLatch latch = new CountDownLatch(N); // 初始化計(jì)數(shù)器為N

    public static void main(String[] args) throws InterruptedException {
        ExecutorService producer = Executors.newFixedThreadPool(2); // 生產(chǎn)者線程池
        ExecutorService consumer = Executors.newFixedThreadPool(2); // 消費(fèi)者線程池

        // 生產(chǎn)者線程
        producer.submit(() -> {
            for (int i = 0; i < N; i++) {
                try {
                    System.out.println("Producer produced " + i);
                    Thread.sleep(100); // 模擬生產(chǎn)過(guò)程需要一定時(shí)間
                    latch.countDown(); // 生產(chǎn)完一個(gè)數(shù)據(jù)后減少計(jì)數(shù)器的值
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // 消費(fèi)者線程
        consumer.submit(() -> {
            try {
                latch.await(); // 在計(jì)數(shù)器歸零之前等待
                System.out.println("All products are produced, consumer can start to consume");
                // 消費(fèi)者開(kāi)始消費(fèi)數(shù)據(jù)...
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        producer.shutdown(); // 關(guān)閉生產(chǎn)者線程池
        consumer.shutdown(); // 關(guān)閉消費(fèi)者線程池
    }
}

在這個(gè)例子中,我們定義了一個(gè) CountDownLatch 的實(shí)例 latch,并初始化為 N。生產(chǎn)者線程會(huì)不斷生產(chǎn)數(shù)據(jù),每次生產(chǎn)完一個(gè)數(shù)據(jù)后調(diào)用 latch.countDown() 方法減少計(jì)數(shù)器的值。消費(fèi)者線程在開(kāi)始消費(fèi)數(shù)據(jù)之前調(diào)用 latch.await() 方法等待計(jì)數(shù)器歸零。當(dāng)所有產(chǎn)品都生產(chǎn)完后,消費(fèi)者才會(huì)開(kāi)始消費(fèi)數(shù)據(jù)。

線程的wait,sleep,join和yield ,notify,notifyAll

  • wait 用于使得當(dāng)前線程等待,直到其他線程用該線程調(diào)用notify或調(diào)用nodifyAll 方法,wait 方法需要在synchronized 塊或方法中調(diào)用,以確保線程間的同步。
  • sleep,用于暫停當(dāng)前線程一段時(shí)間,同時(shí)也建議在synchronized 中調(diào)用。
  • join 用于阻止當(dāng)前線程的執(zhí)行,直到調(diào)用join() 方法的線程結(jié)束,這通常用于等待另外一個(gè)線程完成其任務(wù)。
  • yield 告訴操作系統(tǒng),當(dāng)前線程愿意放棄剩余的時(shí)間片,以使其他線程有機(jī)會(huì)允許,這個(gè)方法并不經(jīng)常使用,因?yàn)樗荒鼙WC一定會(huì)導(dǎo)致其他線程運(yùn)行。
  • notify 這個(gè)方法用于喚醒在此對(duì)象上等待的單個(gè)線程。
  • notifyALl 用于喚醒在此對(duì)象上等待的所以線程。

與多線程相關(guān):Callable,future 和FutureTask

這幾類(lèi)都只能運(yùn)行在線程池中。

  • callable 這是一個(gè)接口,他允許定義一個(gè)有返回值的任務(wù)??梢苑祷厝我忸?lèi)型的結(jié)果,有一個(gè)call 方法,用于執(zhí)行任務(wù)。
  • future 是一個(gè)接口,表示一個(gè)異步計(jì)算的結(jié)果,其中的get方法用于獲取計(jì)算結(jié)果,如果計(jì)算還未完成,則會(huì)阻塞直到計(jì)算完成。
  • futureTask 是future的實(shí)現(xiàn)類(lèi),F(xiàn)utureTask實(shí)現(xiàn)了RunnalbeFuture。因?yàn)镽unnalbeFuture實(shí)現(xiàn)了Runnable 接口,所以這個(gè)可以通過(guò)thread 包裝直接執(zhí)行,也可以提交給ExcuteService 來(lái)執(zhí)行。

ExecutorService 線程池

  • newFixedThreadPool(int corePoolSize): 這個(gè)方法返回一個(gè)線程池,該線程池中的線程數(shù)量是固定的。如果線程池中的線程數(shù)量小于 corePoolSize,那么新的任務(wù)將會(huì)立即啟動(dòng)。如果線程池中的線程數(shù)量已經(jīng)達(dá)到 corePoolSize,那么新的任務(wù)將會(huì)進(jìn)入隊(duì)列等待。
  • newWorkStealingPool(int corePoolSize): 這個(gè)方法返回一個(gè)工作竊取線程池,該線程池中的線程數(shù)量是固定的。這個(gè)線程池的特點(diǎn)是它的線程可以竊取其他線程池隊(duì)列的任務(wù)來(lái)執(zhí)行,這樣可以更有效地利用系統(tǒng)資源。
  • newSingleThreadExecutor(): 這個(gè)方法返回一個(gè)單線程執(zhí)行器,它只會(huì)使用一個(gè)線程來(lái)執(zhí)行任務(wù)。如果這個(gè)線程由于未捕獲的異常而終止,那么一個(gè)新的線程將會(huì)被創(chuàng)建來(lái)代替它。
  • newCachedThreadPool(): 這個(gè)方法返回一個(gè)緩存線程池,它將會(huì)使用一個(gè)緩存來(lái)存儲(chǔ)多余的線程,如果線程池中的線程數(shù)量超過(guò)了需要執(zhí)行的任務(wù)數(shù)量,那么這些多余的線程將會(huì)被緩存起來(lái)等待新的任務(wù)。
  • newSingleThreadScheduledExecutor(): 這個(gè)方法返回一個(gè)單線程調(diào)度執(zhí)行器,它只使用一個(gè)線程來(lái)執(zhí)行定時(shí)任務(wù)或者周期性任務(wù)。
  • newScheduledThreadPool(int corePoolSize): 這個(gè)方法返回一個(gè)定時(shí)調(diào)度執(zhí)行器,你可以用它來(lái)執(zhí)行定時(shí)任務(wù)或者周期性任務(wù)。這個(gè)線程池中的線程數(shù)量可以是固定的,也可以是沒(méi)有限制的。

線程安全

  • StringBuffer
  • Vector:這是一個(gè)舊的集合,線程安全,但是其性能低于ArrayList。Vector的每個(gè)方法都被synchronized修飾,所以在多線程環(huán)境下是安全的。
  • Hashtable:類(lèi)似于HashMap,但是線程安全。所有公共的Hashtable方法都使用synchronized,所以多個(gè)線程可以共享單個(gè)Hashtable。然而,與Vector一樣,Hashtable也沒(méi)有達(dá)到最高的性能。
  • Collections.synchronizedList: 通過(guò)Collections.synchronizedList可以將任何List轉(zhuǎn)換為線程安全的List。
  • Collections.synchronizedMap: 可以將任何Map轉(zhuǎn)換為線程安全的Map
  • Collections.synchronizedSet: 可以將任何Set轉(zhuǎn)換為線程安全的Set。
  • ConcurrentHashMap: 這是一個(gè)線程安全的HashMap實(shí)現(xiàn),設(shè)計(jì)用于高并發(fā)場(chǎng)景。ConcurrentHashMap中的讀取操作可以在沒(méi)有鎖定的情況下進(jìn)行,而寫(xiě)入操作則需要鎖定部分地圖。
  • CopyOnWriteArrayList: 這是一個(gè)線程安全的ArrayList實(shí)現(xiàn)。當(dāng)修改它時(shí),它會(huì)創(chuàng)建并修改一個(gè)新的底層數(shù)組,然后將底層數(shù)組的引用切換到新數(shù)組。這種設(shè)計(jì)使得它在寫(xiě)操作時(shí)復(fù)制數(shù)組,但在讀操作時(shí)不需要鎖定。
  • CopyOnWriteArraySet: 這是一個(gè)線程安全的Set實(shí)現(xiàn),其內(nèi)部使用CopyOnWriteArrayList。
  • BlockingQueue接口的實(shí)現(xiàn),例如ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue, 都是線程安全的。

AysncTask

AsyncTask是Android中一個(gè)非常常用的用于在后臺(tái)線程執(zhí)行異步操作的工具類(lèi)。它可以讓開(kāi)發(fā)人員在主線程之外執(zhí)行耗時(shí)操作,從而避免主線程阻塞,提高應(yīng)用程序的用戶體驗(yàn)。

AsyncTask的基本原理是創(chuàng)建一個(gè)后臺(tái)線程,將耗時(shí)操作放在該線程中執(zhí)行,然后在執(zhí)行完畢后通過(guò)回調(diào)方法將結(jié)果返回給主線程。

AsyncTask類(lèi)需要實(shí)現(xiàn)四個(gè)方法:

  1. onPreExecute():在執(zhí)行后臺(tái)任務(wù)之前被調(diào)用,通常用于在UI線程中執(zhí)行一些預(yù)處理操作,例如顯示一個(gè)加載對(duì)話框。
  2. doInBackground(Params...):在后臺(tái)線程中執(zhí)行耗時(shí)操作的方法。該方法需要傳入一個(gè)參數(shù)列表,用于傳遞數(shù)據(jù)給后臺(tái)任務(wù)。
  3. onProgressUpdate(Progress...):用于在后臺(tái)任務(wù)執(zhí)行過(guò)程中更新UI線程中的進(jìn)度信息。該方法可以在執(zhí)行doInBackground()方法時(shí)調(diào)用,以便將進(jìn)度信息傳遞給UI線程。
  4. onPostExecute(Result):在后臺(tái)任務(wù)執(zhí)行完畢后被調(diào)用。該方法需要傳入一個(gè)參數(shù),表示后臺(tái)任務(wù)的執(zhí)行結(jié)果。在UI線程中執(zhí)行該方法,以便將結(jié)果展示給用戶。

下面是一個(gè)使用AsyncTask的簡(jiǎn)單示例:

public class MyAsyncTask extends AsyncTask<String, Integer, String> {
    private ProgressDialog progressDialog;

    @Override
    protected void onPreExecute() {
        progressDialog = new ProgressDialog(MainActivity.this);
        progressDialog.setMessage("Loading...");
        progressDialog.show();
    }

    @Override
    protected String doInBackground(String... params) {
        // 在后臺(tái)線程中執(zhí)行耗時(shí)操作
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Hello, AsyncTask!";
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        // 在UI線程中更新進(jìn)度信息
        int progress = values[0];
        progressDialog.setProgress(progress);
    }

    @Override
    protected void onPostExecute(String result) {
        // 在UI線程中展示結(jié)果
        progressDialog.dismiss();
        Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
    }
}

線程與進(jìn)程的區(qū)別

  • 地址空間,進(jìn)程有獨(dú)立的地址空間,一個(gè)進(jìn)程崩潰后,在保護(hù)模型下不會(huì)對(duì)其他進(jìn)程產(chǎn)生影響,而線程之間沒(méi)有單獨(dú)的地址空間,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉。

  • 資源擁有關(guān)系:系統(tǒng)會(huì)為進(jìn)程分配資源,如堆空間,地址空間,全局變量等,這些資源會(huì)被其下的線程貢獻(xiàn),系統(tǒng)不會(huì)為線程分配內(nèi)存,線程所使用的資源全部來(lái)源于所屬的進(jìn)程資源。

  • 依賴關(guān)系:一個(gè)進(jìn)程可以包含多個(gè)線程,線程依賴于進(jìn)程。

  • 線程有自己的私有屬性,如TCB線程控制塊,線程id,寄存器,硬件上下文,這些都不會(huì)被共享,而進(jìn)程的私有屬性,包括進(jìn)程控制塊PCB。

  • 創(chuàng)建方式:進(jìn)程是系統(tǒng)分配資源的最小單位,可以通過(guò)fork 函數(shù)創(chuàng)建子進(jìn)程,而線程是程序執(zhí)行的最小單位,通過(guò)線程的創(chuàng)建,同步,通信和銷(xiāo)毀等操作實(shí)現(xiàn)。

  • 開(kāi)銷(xiāo):進(jìn)程需要?jiǎng)?chuàng)建獨(dú)立的內(nèi)存空間和資源,因此開(kāi)銷(xiāo)較大。

  • 并發(fā)性:進(jìn)程不收其他進(jìn)程影響,多個(gè)線程存在并發(fā),共享內(nèi)存及其通信。

  • 獨(dú)立性:進(jìn)程擁有獨(dú)立的內(nèi)存空間和系統(tǒng)資源,不受其他進(jìn)程影響。而一個(gè)線程崩潰,會(huì)導(dǎo)致進(jìn)程崩潰。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容