線程相關(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è)方法:
-
onPreExecute():在執(zhí)行后臺(tái)任務(wù)之前被調(diào)用,通常用于在UI線程中執(zhí)行一些預(yù)處理操作,例如顯示一個(gè)加載對(duì)話框。 -
doInBackground(Params...):在后臺(tái)線程中執(zhí)行耗時(shí)操作的方法。該方法需要傳入一個(gè)參數(shù)列表,用于傳遞數(shù)據(jù)給后臺(tái)任務(wù)。 -
onProgressUpdate(Progress...):用于在后臺(tái)任務(wù)執(zhí)行過(guò)程中更新UI線程中的進(jìn)度信息。該方法可以在執(zhí)行doInBackground()方法時(shí)調(diào)用,以便將進(jìn)度信息傳遞給UI線程。 -
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)程崩潰。