編輯:關於Android編程
這篇文章介紹的幾個問題:
1 、進程和線程,以及區別
2、Android中的進程
3、多線程
4、線程同步
5、進程間通信
6、Handler、MessageQuere、Runnable、Looper
一 、進程和線程,以及區別
進程(Process):當一個程序進入內存運行時,即變成一個進程。進程是處於運行過程中的程序,是程序的一個運行實例。 進程是操作系統進行資源分配和調度的一個獨立單位。
線程(Thread):線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。
並發和並行
並發:是指在同一時間點只能有一條指令執行,但多個進程指令被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果。
並行:指在同一時間點,有多條指令在多個處理器上同時執行。
·
進程和線程的區別
線程是進程的組成部分,一個進程可以有很多線程,每條線程並行執行不同的任務。
不同的進程使用不同的內存空間,而線程與父進程的其他線程共享父進程的所擁有的全部資源。這樣編程方便了,但是要更加小心。
別把內存空間和棧內存搞混,每個線程都擁有單獨的棧內存用來存儲本地數據。線程擁有自己的堆棧、自己的程序計數器和自己的局部變量,但不擁有系統資源。
線程的調度和管理由進程本身負責完成。操作系統對進程進行調度,管理和資源分配。
二 、Android中的進程
Android存在五種級別的進程:前台進程、可見進程、服務進程、後台進程、空進程。
前台進程(foreground process):前台進程是用戶當前正在使用的進程。
存在前台進程的條件:
- 進程中的某個Activity正在與用戶進行交互(Activity的onResume()方法被調用);
- 綁定到與當前用戶正在交互的activity的Service所在的進程;
- 進程中的某個Service正運行在前台,即這個service的startForeground()方法被調用;
- 進程中的某個Service正在執行生命周期回調方法(比如,onCreate(),onStart(),或者onDeatroy());
- 進程中的BroadcastReceiver正在執行onReceive()方法;
可見進程(visible process):可視進程是指沒有前台運行的組件,但仍然會對用戶在屏幕看到的內容造成影響的進程。
存在可見進程的條件:
- 進程運行的Activity不在前台,但仍然是可見的(調用了onPause()方法)。這種情況可能是這樣的,正在前台運行的Activity啟動了一個對話框,這個對話框懸浮在這個activity之上,但仍有部分可見;
- 進程中的Service綁定到了一個可視(或前台)的activity(該activity已調用了onPause()方法);
服務進程(service process):運行著一個通過startService() 方法啟動的service,這個service不屬於上面提到的2種更高重要性的。
service所在的進程雖然對用戶不是直接可見的,但是他們執行了用戶非常關注的任務(比如播放mp3,從網絡下載數據)。只要前台進程和可見進程有足夠的內存,系統不會回收他們。
後台進程(background process):後台進程是指進程中的activity當前對用戶來說不可見(這個activity調用了onStop()方法)。
後台進程不會對用戶的體驗造成任何影響,並且系統可以在前台進程、可視進程、服務繼承需要內存資源的時候會殺死後台進程。通常會有很多後台進程運行,並且這些後台進程保存在一個最近使用列表中,這樣做的好處就是保證用戶最近看到的進程最後被殺死。如果一個activity已經正確的實現了生命周期方法,並且保存了當前的狀態,那麼系統殺死這些後台進程對用戶的可視效果來說的話,沒有任何影響,因為當用戶返回回來的時候,這個activity已經保存了所有的可視狀態。
空進程(empty process):一個空進程沒有任何運行的程序組件。
系統保持空進程存在的唯一原因就是為了緩存方面的考慮,這樣做主要是為了提高組件的啟動時間。系統經常會殺死這些空進程來保持整個系統資源和內核緩存之間的平衡。
因為一個正在運行的服務所在的進程的重要性高於一個處於後台的activity所在的進程,所以根據這一點,如果一個activity如果要執行需要長時間運行的操作的話,這個activity最好為該操作啟動一個新的服務,而不是僅僅創建一個工作線程,尤其是當這個工作線程運行的時間可能比該activity的運行時間還長的時候。
三 、多線程
為什麼Android是線程不安全的?
Android單線程模型的兩個原則:不能阻塞UI線程;不要再UI線程外訪問Android UI toolkit。
也就是說,在非UI線程操作UI 和 在UI線程進行耗時操作都會出現錯誤。
既然耗時操作不能再UI線程中進行,我們當然會想到新開線程處理耗時操作,這就會出現多線程的問題。同時,耗時操作在單獨的進程中完成後,得到的結果必須要在UI線程展示,就會涉及進程間通信的問題。
Java創建線程的方法:
繼承Thread類創建線程類實現Runnable接口創建線程類1、定義Thread類的子類,重寫該類的run()方法。該方法為線程執行體;
2、創建Thread子類的實例。即線程對象;
3、調用線程對象的start()方法啟動該線程;
1、定義Runnable接口的實現類,重寫該接口的run()方法。該方法為線程執行體;
2、創建Runnable實現類的實例。並以此實例作為Thread的target來創建Thread對象。該Thread對象才是真正的線程對象;
3、調用線程對象(該Thread對象)的start()方法啟動該線程;
Android中多線程的幾種工具類:
AsyncTask
HandlerThread
ThreadPool
IntentService
四 、線程同步
線程同步:當使用多個線程來訪問同一個數據時,非常容易出現線程安全問題(比如多個線程都在操作同一數據導致數據不一致),所以我們用同步機制來解決這些問題。線程同步的目的就是避免線程“同步”執行。
同步機制既可以同步代碼塊、又可以同步方法:
//同步代碼塊 synchronized (obj) { ... } //同步方法 public synchronized void methodName() { .... }
當使用synchronized 來修飾某個共享資源時,當某個線程獲得共享資源的鎖後就可以執行相應的代碼段,直到該線程運行完該代碼段後才釋放對該共享資源的鎖,讓其他線程有機會執行對該共享資源的修改。當某個線程占有某個共享資源的鎖時,如果另外一個線程也想獲得這把鎖運行就需要使用wait() 和notify()/notifyAll()方法來進行線程通訊了。
線程同步的特征
1、 如果一個同步代碼塊和非同步代碼塊同時操作共享資源,仍然會造成對共享資源的競爭。因為當一個線程執行一個對象的同步代碼塊時,其他的線程仍然可以執行對象的非同步代碼塊。(所謂的線程之間保持同步,是指不同的線程在執行同一個對象的同步代碼塊時,因為要獲得對象的同步鎖而互相牽制)
2、 每個對象都有唯一的同步鎖
3、 在靜態方法前面可以使用synchronized修飾符。
4、 當一個線程開始執行同步代碼塊時,並不意味著必須以不間斷的方式運行,進入同步代碼塊的線程可以執行Thread.sleep()或執行Thread.yield()方法,此時它並不釋放對象鎖,只是把運行的機會讓給其他的線程。
5、 Synchronized聲明不會被繼承,如果一個用synchronized修飾的方法被子類覆蓋,那麼子類中這個方法不在保持同步,除非用synchronized修飾。
死鎖
線程1獨占(鎖定)資源A,等待獲得資源B後,才能繼續執行;
線程2獨占(鎖定)資源B,等待獲得資源A後,才能繼續執行;
這樣就會發生死鎖,程序無法正常執行。
為避免死鎖,當幾個線程都要訪問共享資源A、B、C 時,保證每個線程都按照同樣的順序去訪問他們。
lock和synchronized:
總的來說,lock更加靈活。
主要相同點:Lock能完成synchronized所實現的所有功能
不同:
1.ReentrantLock功能性方面更全面,比如時間鎖等候,可中斷鎖等候,鎖投票等,因此更有擴展性。在多個條件變量和高度競爭鎖的地方,用ReentrantLock更合適,ReentrantLock還提供了Condition,對線程的等待和喚醒等操作更加靈活,一個ReentrantLock可以有多個Condition實例,所以更有擴展性。
2.ReentrantLock必須在finally中釋放鎖,否則後果很嚴重,編碼角度來說使用synchronized更加簡單,不容易遺漏或者出錯。
3.ReentrantLock 的性能比synchronized會好點。
4.ReentrantLock提供了可輪詢的鎖請求,他可以嘗試的去取得鎖,如果取得成功則繼續處理,取得不成功,可以等下次運行的時候處理,所以不容易產生死鎖,而synchronized則一旦進入鎖請求要麼成功,要麼一直阻塞,所以更容易產生死鎖。
1、ReentrantLock 擁有Synchronized相同的並發性和內存語義,此外還多了 鎖投票,定時鎖等候和中斷鎖等候
線程A和B都要獲取對象O的鎖定,假設A獲取了對象O鎖,B將等待A釋放對O的鎖定,
如果使用 synchronized ,如果A不釋放,B將一直等下去,不能被中斷
如果 使用ReentrantLock,如果A不釋放,可以使B在等待了足夠長的時間以後,中斷等待,而干別的事情
ReentrantLock獲取鎖定與三種方式:
a) lock(), 如果獲取了鎖立即返回,如果別的線程持有鎖,當前線程則一直處於休眠狀態,直到獲取鎖
b) tryLock(), 如果獲取了鎖立即返回true,如果別的線程正持有鎖,立即返回false;
c) tryLock (long timeout, TimeUnit unit), 如果獲取了鎖定立即返回true,如果別的線程正持有鎖,會等待參數給定的時間,在等待的過程中,如果獲取了鎖定,就返回true,如果等待超時,返回false;
d) lockInterruptibly:如果獲取了鎖定立即返回,如果沒有獲取鎖定,當前線程處於休眠狀態,直到或者鎖定,或者當前線程被別的線程中斷
2、synchronized是在JVM層面上實現的,不但可以通過一些監控工具監控synchronized的鎖定,而且在代碼執行時出現異常,JVM會自動釋放鎖定,但是使用Lock則不行,lock是通過代碼實現的,要保證鎖定一定會被釋放,就必須將 unLock()放到finally{} 中
3、在資源競爭不是很激烈的情況下,Synchronized的性能要優於ReetrantLock,但是在資源競爭很激烈的情況下,Synchronized的性能會下降幾十倍,但是ReetrantLock的性能能維持常態;
五 、進程間通信
進程間通信:Inter-process communication (IPC)是指運行在不同進程(無論是否是同一台機器)中的若干線程間的數據交換。
進程間通信的兩種方法:文件共享、操作系統提供的公共信息機制。
計算機進程間通信的幾種機制:
共享內存(Shared Memory)通過訪問公共內存空間。
管道(Pipe)管道也是操作系統中常見的一種進程間通信方式,管道是單向的,如果同時有讀和寫的操作,就需要建立兩根管道。
UDS(Unix Domain Socket)Socket在網絡通信領域獲得了廣泛的應用,被稱為Network Socket,對於同一台機器的進程間通信,他也完全能夠勝任。UDS是專門針對單機內的進程間通信提出來的,有時也被成為IPC Socket。
Android中使用最多的一種IPC機制是Binder,其次就是UDS。
RPC (Remote Procedure Calls)RPC設計的通信雙方通常運行與兩台不同的機器中。
六 、Handler、MessageQuere、Runnable、Looper
message
message是消息內容;
messageQuere
messageQuere是消息隊列,裡面存很多的message;
handler
消息的真正處理者;
通知MQ它要執行一個任務(sendMessage),並在loop到自己的時候執行該任務(handleMessage),整個過程是異步的。
looper
looper管理進程中的MessageQuere,負責循環消息;
runnable
Runnable和Message可以被壓入某個MessageQueue中,形成一個集合
本文主要為大家分享了Android實現搜索功能,並且可以實時顯示搜索的歷史記錄,根據輸入的內容去模糊查詢,供大家參考,界面圖如下。 本案例實現起來也非常的簡單,
我們先來看一個小例子:可以看到,效果實現的也是很棒,比之前自定義的標簽指示器更加的流暢。下面,簡單介紹一下 PagerTabStrip和它的使用。PagerTabStri
在安卓手機上,不少用戶都會遇過com.android.phone已停止的彈窗,尤其經常刷機的最明顯。導致的原因實在太多,有刷機步驟不對的,亂改系統文件的,這
一、簡介本節演示如何在安卓系統中通過用戶配置文件(user profile)讀取和更新該手機的所有聯系人信息,以及如何導航到用戶配置文件中的這些聯系人。二、基本概念&nb