日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 多线程之几个基本问题

發(fā)布時(shí)間:2023/12/9 Android 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 多线程之几个基本问题 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Android中的進(jìn)程和線程

  • Android中的一個(gè)應(yīng)用程序一般就對應(yīng)著一個(gè)進(jìn)程,多進(jìn)程的情況可以參考Android 多進(jìn)程通信之幾個(gè)基本問題
  • Android中更常見的是多線程的情況,一個(gè)應(yīng)用程序中一般都有包括UI線程等多個(gè)線程。Android中規(guī)定網(wǎng)絡(luò)訪問必須在子線程中進(jìn)行,而操作更新UI則只能在UI線程。
  • 常見的網(wǎng)絡(luò)請求庫,如OkHttp、Volly等都為我們封裝好了線程池,所以我們在進(jìn)行網(wǎng)絡(luò)請求時(shí)一般不是很能直觀地感受到創(chuàng)建線程以及切換線程的過程。
  • 線程是一種很寶貴的資源,要避免頻繁創(chuàng)建銷毀線程,一般推薦用線程池來管理線程。

線程的狀態(tài)

線程可能存在6種不同的狀態(tài):新創(chuàng)建(New)、可運(yùn)行(Runnable)、阻塞狀態(tài)(Blocked)、等待狀態(tài)(Waiting)、限期等待(Timed Waiting)、終止?fàn)顟B(tài)(Terminated)

  • 新創(chuàng)建(New):創(chuàng)建后但還未啟動(dòng)的線程(還沒有調(diào)用start方法)處于這種狀態(tài)
  • 可運(yùn)行(Runnable):一旦調(diào)用了start方法,線程就處于這種狀態(tài)。需要注意的是此時(shí)線程可能正在執(zhí)行,也可能在等待CPU分配執(zhí)行的時(shí)間
  • 阻塞狀態(tài)(Blocked):表示線程被鎖阻塞,等待獲取到一個(gè)排他鎖。在程序等待進(jìn)入同步區(qū)域時(shí),線程將進(jìn)入這種狀態(tài)
  • 等待狀態(tài)(Waiting):處于這種狀態(tài)的線程不會(huì)被分配CPU執(zhí)行時(shí)間,它們要等待被其他線程顯示地喚醒。調(diào)用以下方法會(huì)讓線程進(jìn)入這種狀態(tài):

    • 沒有設(shè)置Timeout參數(shù)的Object.wait()方法
    • 沒有設(shè)置Timeout參數(shù)的Thread.join()方法
  • 限期等待(Timed Waiting):與等待狀態(tài)(Waiting)不同的是,處于這種狀態(tài)的線程不需要等待其它線程喚醒,在一定時(shí)間之后會(huì)由系統(tǒng)喚醒。調(diào)用以下方法會(huì)讓線程進(jìn)入這種狀態(tài):

    • Thread.sleep()方法
    • 設(shè)置了Timeout參數(shù)的Object.wait()方法
    • 設(shè)置了Timeout參數(shù)的Thread.join()方法
  • 終止?fàn)顟B(tài)(Terminated):表示線程已經(jīng)執(zhí)行完畢。導(dǎo)致線程終止有2種情況:

    • 線程的run方法執(zhí)行完畢,正常退出
    • 因?yàn)橐粋€(gè)沒有捕獲的異常而終止了run方法

創(chuàng)建線程

創(chuàng)建線程一般有如下幾種方式:繼承Thread類;實(shí)現(xiàn)Runnable接口;實(shí)現(xiàn)Callable接口

  • 繼承Thread類,重寫run方法
public class TestThread extends Thread {@Overridepublic void run() {System.out.println("Hello World");}public static void main(String[] args) {Thread mThread = new TestThread();mThread.start();} }
  • 實(shí)現(xiàn)Runnable接口,并實(shí)現(xiàn)run方法
public class TestRunnable implements Runnable {@Overridepublic void run() {System.out.println("Hello World");}public static void main(String[] args) {TestRunnable mTestRunnable = new TestRunnable();Thread mThread = new Thread(mTestRunnable);mThread.start();} }
  • 實(shí)現(xiàn)Callable接口,重寫call方法

    • Callable可以在任務(wù)接受后提供一個(gè)返回值而Runnable不行
    • Callable的call方法可以拋出異常,Runnable的run方法不行
    • 運(yùn)行Callable可以拿到一個(gè)Future對象,表示計(jì)算的結(jié)果,通過Future的get方法可以拿到異步計(jì)算的結(jié)果,不過當(dāng)前線程會(huì)阻塞。
public class TestCallable {public static class MyTestCallable implements Callable<String> {@Overridepublic String call() throws Exception {//call方法可以提供返回值,而Runnable不行return "Hello World";}}public static void main(String[] args) {MyTestCallable myTestCallable = new MyTestCallable();//手動(dòng)創(chuàng)建線程池ExecutorService executorService = new ThreadPoolExecutor(1,1,0L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(10));//運(yùn)行callable可以拿到一個(gè)Future對象Future future = executorService.submit(myTestCallable);try {//等待線程結(jié)束,future.get()方法會(huì)使當(dāng)前線程阻塞System.out.println(future.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}} }
  • 以上三種方式就是常見的創(chuàng)建線程的方式。推薦使用實(shí)現(xiàn)Runnable接口的方法。

線程中斷

  • 當(dāng)一個(gè)線程調(diào)用interrupt方法時(shí),線程的中斷標(biāo)識為將被設(shè)置成true
  • 通過Thread.currentThread().isInterrupted()方法可以判斷線程是否應(yīng)該被中斷
  • 可以通過調(diào)用Thread.interrupted()對中斷標(biāo)志位進(jìn)行復(fù)位(設(shè)置為false)
  • 如果一個(gè)線程處于阻塞狀態(tài),線程在檢查中斷標(biāo)志位時(shí)如果發(fā)現(xiàn)中斷標(biāo)志位為true,則會(huì)在阻塞方法處拋出InterruptedException異常,并且在拋出異常前會(huì)將中斷標(biāo)志位復(fù)位,即重新設(shè)置為false
  • 不要在代碼底層捕獲InterruptedException異常后不做處理

同步的幾種方法

同步的方式一般有如下3種:volatile關(guān)鍵字、synchronized關(guān)鍵字、重入鎖ReentrantLock

volatile關(guān)鍵字
  • volatile關(guān)鍵字實(shí)現(xiàn)多線程安全關(guān)鍵在于它的可見性特性,但它需要滿足一些條件才能保證線程安全,具體可以查看文章深入理解Java虛擬機(jī)(八)之Java內(nèi)存模型
  • 在用volatile關(guān)鍵字來實(shí)現(xiàn)多線程安全時(shí)需要注意volatile不保證原子性,也就是不能用于一些自增、自減等操作,也不能用于一些不變式中,自增、自減比較好理解,下面看看不變式的情況
public class VolatileTest {private volatile int lower,upper;public int getLower() {return lower;}public void setLower(int value) {if (value > upper) {throw new IllegalArgumentException();}this.lower = value;}public int getUpper() {return upper;}public void setUpper(int value) {if (value < lower) {throw new IllegalArgumentException();}this.upper = value;} }
  • 上面的例子中,如果初始值是(0,5),線程A調(diào)用setLower(4),線程B調(diào)用setUpper(3),顯然最后結(jié)果就會(huì)變成(4,3)了
  • volatile使用的場景常見的有作為狀態(tài)標(biāo)志以及DCL單例模式
synchronized關(guān)鍵字和重入鎖ReentrantLock
  • synchronized關(guān)鍵字比較常見,可以用于同步方法也可以用于同步代碼塊,一般推薦用同步方法,同步代碼塊的安全性不高。
  • 重入鎖ReentrantLock相比synchronized提供了一些獨(dú)有的特性:可以綁定多個(gè)解鎖的條件Condition、可以實(shí)現(xiàn)公平鎖、可以設(shè)置放棄等待獲取鎖的時(shí)間。
public class ReentrantLockTest {private Lock mLock = new ReentrantLock();//true,表示實(shí)現(xiàn)公平鎖<!--private Lock mLock = new ReentrantLock(true);-->private Condition condition;private void thread1() throws InterruptedException{mLock.lock();try {condition = mLock.newCondition();condition.await();System.out.println("thread1:Hello World");}finally {mLock.unlock();}}private void thread2() throws InterruptedException{mLock.lock();try {System.out.println("thread2:Hello World");condition.signalAll();}finally {mLock.unlock();}} }
  • 一個(gè)ReentrantLock有多個(gè)相關(guān)的Condition,調(diào)用Condition的await方法會(huì)讓當(dāng)前線程進(jìn)入該條件的等待集并阻塞,直到另一個(gè)線程調(diào)用了同一個(gè)條件的signalAll方法激活因?yàn)檫@個(gè)條件而進(jìn)入阻塞的所有線程
  • 一般線程同步用得比較多的還是synchronized同步方法和一些java.util.concurrent包提供的一些類

如何安全的終止線程

雖然我們一般都是利用線程池來管理線程而不會(huì)直接顯示地創(chuàng)建線程,但是作為線程相關(guān)知識的一部分,我們還是要了解如何安全地終止一個(gè)線程。

要安全地終止一個(gè)線程,一般有2種方法:中斷和標(biāo)志位

(1)利用中斷來終止線程

Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while (!Thread.currentThread().isInterrupted()) {//do something}} });//當(dāng)我們調(diào)用Thread的interrupt方法時(shí),線程就會(huì)退出循環(huán)停止了。 thread.interrupt();

(2)通過標(biāo)志位

private static class MyRunnable implements Runnable {//控制線程的標(biāo)志位,需要用 volatile關(guān)鍵字 private volatile boolean on = true;@Overridepublic void run() {while (on) {//do something }}public void cancel() {on = false;} }//啟動(dòng)線程 MyRunnable myRunnable = new MyRunnable(); Thread thread = new Thread(myRunnable);//終止線程 myRunnable.cancel();
歡迎關(guān)注我的微信公眾號,期待與你一起學(xué)習(xí),一起交流,一起成長!

總結(jié)

以上是生活随笔為你收集整理的Android 多线程之几个基本问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。