導航:首頁 > 操作系統 > android線程信號量

android線程信號量

發布時間:2022-09-13 07:30:18

1. android 子線程訪問網路超時怎麼辦

Android開發中經常需要調用線程訪問網路,而手機的網路信號經常斷斷續續,容易出現網路超時的情況,這種情況下後台線程往往得不到關閉,浪費系統資源。
在下面的例子中使用了java 中的Timer類,對線程進行了約束,如果線程在一定時間內為響應則終止該線程。
import java.util.Timer;
import java.util.TimerTask;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.app.ProgressDialog;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {
private static final int TIME_OUT = 0;
private static final int SUCCESS = 1;
// 超時的時限為5秒
private static final int TIME_LIMIT = 5000;
ProgressDialog proDialog;
Timer timer;
Thread thread;
Button btn1, btn2;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button) findViewById(R.id.button1);
btn2 = (Button) findViewById(R.id.button2);
// 測試未超時的線程,為btn1綁定事件
btn1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
proDialog = ProgressDialog.show(MainActivity.this, "提示",
"線程運行中");
// 匿名內部線程
thread = new Thread() {
@Override
public void run() {
while (true) {
try {
//線程休眠時間,超時
sleep(10000);
} catch (InterruptedException e) {
break;
}
}

}
};
thread.start();
// 設定定時器
timer = new Timer();
timer.schele(new TimerTask() {
@Override
public void run() {
sendTimeOutMsg();
}
}, TIME_LIMIT);

}
});
// 測試超時的線程,為btn2綁定事件
btn2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {

proDialog = ProgressDialog.show(MainActivity.this, "提示",
"線程運行中");
// 匿名內部線程
thread = new Thread() {
public void run() {
try {
// 線程休眠時間,未超時
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msgSuc = new Message();
msgSuc.what = SUCCESS;
myHandler.sendMessage(msgSuc);
}
};
thread.start();
// 設定定時器
timer = new Timer();
timer.schele(new TimerTask() {
@Override
public void run() {
sendTimeOutMsg();
}
}, TIME_LIMIT);
}
});
}
// 接收消息的Handler
final Handler myHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case TIME_OUT:
//打斷線程
thread.interrupt();
proDialog.dismiss();
Toast.makeText(MainActivity.this, "線程超時", Toast.LENGTH_SHORT)
.show();
break;
case SUCCESS:
//取消定時器
timer.cancel();
proDialog.dismiss();
Toast.makeText(MainActivity.this, "線程運行完成", Toast.LENGTH_SHORT)
.show();
break;
default:
break;
}
};
};
//向handler發送超時信息
private void sendTimeOutMsg() {
Message timeOutMsg = new Message();
timeOutMsg.what = TIME_OUT;
myHandler.sendMessage(timeOutMsg);
}

}

2. Android多線程的四種方式:Handler、AsyncTask、ThreadPoolExector、IntentService

     非同步通信機制,將工作線程中需更新UI的操作信息 傳遞到 UI主線程,從而實現 工作線程對UI的更新處理,最終實現非同步消息的處理。Handler不僅僅能將子線程的數據傳遞給主線程,它能實現任意兩個線程的數據傳遞。

(1)Message

    Message 可以在線程之間傳遞消息。可以在它的內部攜帶少量數據,用於在不同線程之間進行數據交換。除了 what 欄位,還可以使用 arg1 和 arg2 來攜帶整型數據,使用 obj 來攜帶 Object 數據。

(2) Handler

    Handler 作為處理中心,用於發送(sendMessage 系列方法)與處理消息(handleMessage 方法)。

(3) MessageQueue

    MessageQueue 用於存放所有通過 Handler 發送的消息。這部分消息會一直存放在消息隊列中,直到被處理。每個線程中只會有一個 MessageQueue 對象

(4) Looper

    Looper 用於管理 MessageQueue 隊列,Looper對象通過loop()方法開啟了一個死循環——for (;;){},不斷地從looper內的MessageQueue中取出Message,並傳遞到 Handler 的 handleMessage() 方法中。每個線程中只會有一個 Looper 對象。

    AsyncTask 是一種輕量級的任務非同步類,可以在後檯子線程執行任務,且將執行進度及執行結果傳遞給 UI 線程。

(1)onPreExecute()

    在 UI 線程上工作,在任務執行 doInBackground() 之前調用。此步驟通常用於設置任務,例如在用戶界面中顯示進度條。

(2)doInBackground(Params... params)

    在子線程中工作,在 onPreExecute() 方法結束後執行,這一步被用於在後台執行長時間的任務,Params 參數通過 execute(Params) 方法被傳遞到此方法中。任務執行結束後,將結果傳遞給 onPostExecute(Result) 方法,同時我們可以通過 publishProgress(Progress) 方法,將執行進度發送給 onProgressUpdate(Progress) 方法。

(3)onProgressUpdate(Progress... values)

    在 UI 線程上工作,會在 doInBackground() 中調用 publishProgress(Progress) 方法後執行,此方法用於在後台計算仍在執行時(也就是 doInBackgound() 還在執行時)將計算執行進度通過 UI 顯示出來。例如,可以通過動畫進度條或顯示文本欄位中的日誌,從而方便用戶知道後台任務執行的進度。

(4)onPostExecute(Result result)

    在 UI 線程上工作,在任務執行完畢(即 doInBackground(Result) 執行完畢)並將執行結果傳過來的時候工作。

使用規則:

(1)AsyncTask 是個抽象類,所以要創建它的子類實現抽象方法

(1)AsyncTask 類必須是在 UI 線程中被載入,但在Android 4.1(API 16)開始,就能被自動載入完成。

(2)AsyncTask 類的實例對象必須在 UI 線程中被創建。

(3)execute() 方法必須是在 UI 線程中被調用。

(4)不要手動調用方法 onPreExecute()、onPostExecute()、doInBackground()、onProgressUpdate()

(5)任務只能執行一次(如果嘗試第二次執行,將拋出異常)。即一個AsyncTask對象只能調用一次execute()方法。

原理:

          其源碼中原理還是 Thread 與 Handler 的實現,其包含 兩個線程池,一個 Handler,如下所示:

名稱類型作用

SERIAL_EXECUTOR線程池分發任務,串列分發,一次只分發一個任務

THREAD_POOL_EXECUTOR線程池執行任務,並行執行,執行的任務由 SERIAL_EXECUTOR 分發

InternalHandlerHandler負責子線程與主線程的溝通,通知主線程做 UI 工作

    一方面減少了每個並行任務獨自建立線程的開銷,另一方面可以管理多個並發線程的公共資源,從而提高了多線程的效率。所以ThreadPoolExecutor比較適合一組任務的執行。Executors利用工廠模式對ThreadPoolExecutor進行了封裝。

Executors提供了四種創建ExecutorService的方法,他們的使用場景如下:

1. Executors.newFixedThreadPool()

    創建一個定長的線程池,每提交一個任務就創建一個線程,直到達到池的最大長度,這時線程池會保持長度不再變化。

當線程處於空閑狀態時,它們並不會被回收,除非線程池被關閉。當所有的線程都處於活動狀態時,新任務都會處於等待狀態,直到有線程空閑出來。

只有核心線程並且不會被回收,能夠更加快速的響應外界的請求。

2. Executors.newCachedThreadPool()

    創建一個可緩存的線程池,如果當前線程池的長度超過了處理的需要時,它可以靈活的回收空閑的線程,當需要增加時,它可以靈活的添加新的線程,而不會對池的長度作任何限制

    線程數量不定的線程池,只有非核心線程,最大線程數為 Integer.MAX_VALUE。當線程池中的線程都處於活動狀態時,線程池會創建新的線程來處理新任務,否則利用空閑的線程來處理新任務。線程池中的空閑線程具有超時機制,為 60s。

    任務隊列相當於一個空集合,導致任何任務都會立即被執行,適合執行大量耗時較少的任務。當整個線程池都處於限制狀態時,線程池中的線程都會超時而被停止。

3. Executors.newScheledThreadPool()

    創建一個定長的線程池,而且支持定時的以及周期性的任務執行,類似於Timer。

    非核心線程數沒有限制,並且非核心線程閑置的時候立即回收,主要用於執行定時任務和具有固定周期的重復任務。

4. Executors.newSingleThreadExecutor()

    創建一個單線程化的executor,它只創建唯一的worker線程來執行任務

    只有一個核心線程,保證所有的任務都在一個線程中順序執行,意義在於不需要處理線程同步的問題。

    一般用於執行後台耗時任務,當任務執行完成會自動停止;同時由於它是一個服務,優先順序要遠遠高於線程,更不容易被系統殺死,因此比較適合執行一些高優先順序的後台任務。

使用步驟:創建IntentService的子類,重寫onHandleIntent方法,在onHandleIntent中執行耗時任務

    原理:在源碼實現上,IntentService封裝了HandlerThread和Handler。onHandleIntent方法結束後會調用IntentService的stopSelf(int startId)方法嘗試停止服務。

    IntentService的內部是通過消息的方式請求HandlerThread執行任務,HandlerThread內部又是一種使用Handler的Thread,這就意味著IntentService和Looper一樣是順序執行後台任務的

(HandlerThread:封裝了Handler + ThreadHandlerThread適合在有需要一個工作線程(非UI線程)+任務的等待隊列的形式,優點是不會有堵塞,減少了對性能的消耗,缺點是不能同時進行多個任務的處理,需要等待進行處理。處理效率低,可以當成一個輕量級的線程池來用)

3. 能主動讓android主線程等待1s嗎

當然可以啊,你在主線程中
try {
Thread.sleep(1000); //就是當前線程暫停1000毫秒
} catch (Exception e) {
// TODO: handle exception
}

4. Android 進程間通信的幾種實現方式

Android 進程間通信的幾種實現方式

主要有4種方式:

這4種方式正好對應於android系統中4種應用程序組件:Activity、Content Provider、Broadcast和Service。

主要實現原理:

由於應用程序之間不能共享內存。為了在不同應用程序之間交互數據(跨進程通訊),AndroidSDK中提供了4種用於跨進程通訊的方式進行交互數據,實現進程間通信主要是使用sdk中提供的4組組件根據實際開發情況進行實現數據交互。

詳細實現方式:

Acitivity實現方式

Activity的跨進程訪問與進程內訪問略有不同。雖然它們都需要Intent對象,但跨進程訪問並不需要指定Context對象和Activity的 Class對象,而需要指定的是要訪問的Activity所對應的Action(一個字元串)。有些Activity還需要指定一個Uri(通過 Intent構造方法的第2個參數指定)。 在android系統中有很多應用程序提供了可以跨進程訪問的Activity,例如,下面的代碼可以直接調用撥打電話的Activity。

IntentcallIntent=newIntent(Intent.ACTION_CALL,Uri.parse("tel:12345678");
startActivity(callIntent);


Content Provider實現方式

Android應用程序可以使用文件或SqlLite資料庫來存儲數據。Content Provider提供了一種在多個應用程序之間數據共享的方式(跨進程共享數據)

應用程序可以利用Content Provider完成下面的工作

1. 查詢數據
2. 修改數據
3. 添加數據
4. 刪除數據

Broadcast 廣播實現方式

廣播是一種被動跨進程通訊的方式。當某個程序向系統發送廣播時,其他的應用程序只能被動地接收廣播數據。這就象電台進行廣播一樣,聽眾只能被動地收聽,而不能主動與電台進行溝通。在應用程序中發送廣播比較簡單。只需要調用sendBroadcast方法即可。該方法需要一個Intent對象。通過Intent對象可以發送需要廣播的數據。


Service實現方式

常用的使用方式之一:利用AIDL Service實現跨進程通信

這是我個人比較推崇的方式,因為它相比Broadcast而言,雖然實現上稍微麻煩了一點,但是它的優勢就是不會像廣播那樣在手機中的廣播較多時會有明顯的時延,甚至有廣播發送不成功的情況出現。

注意普通的Service並不能實現跨進程操作,實際上普通的Service和它所在的應用處於同一個進程中,而且它也不會專門開一條新的線程,因此如果在普通的Service中實現在耗時的任務,需要新開線程。

要實現跨進程通信,需要藉助AIDL(Android Interface Definition Language)。Android中的跨進程服務其實是採用C/S的架構,因而AIDL的目的就是實現通信介面。


總結

跨進程通訊這個方面service方式的通訊遠遠復雜於其他幾種通訊方式,實際開發中Activity、Content Provider、Broadcast和Service。4種經常用到,學習過程中要對沒種實現方式有一定的了解。

5. 如何在Android JNI編程中實現對信號量的操作

可以。實現JNI原生函數源文件: 新建com_lucyfyr_HelloWorld.c文件: #include #define LOG_TAG "HelloWorld" #include /* Native interface, it will be call in java code */ JNIEXPORT jstring JNICALL Java_com_lucyfyr_HelloWorld_printJNI...

6. 針對Android的性能優化集中哪些方面

一、概要:

本文主要以Android的渲染機制、UI優化、多線程的處理、緩存處理、電量優化以及代碼規范等幾方面來簡述Android的性能優化

二、渲染機制的優化:

大多數用戶感知到的卡頓等性能問題的最主要根源都是因為渲染性能。

Android系統每隔16ms發出VSYNC信號,觸發對UI進行渲染, 如果每次渲染都成功,這樣就能夠達到流暢的畫面所需要的60fps,為了能夠實現60fps,這意味著程序的大多數操作都必須在16ms內完成。

*關於JobScheler的更多知識可以參考http://hukai.me/android-training-course-in-chinese/background-jobs/scheling/index.html

七、代碼規范

1)for loop中不要聲明臨時變數,不到萬不得已不要在裡面寫try catch。

2)明白垃圾回收機制,避免頻繁GC,內存泄漏,OOM(有機會專門說)

3)合理使用數據類型,StringBuilder代替String,少用枚舉enum,少用父類聲明(List,Map)

4)如果你有頻繁的new線程,那最好通過線程池去execute它們,減少線程創建開銷。

5)你要知道單例的好處,並正確的使用它。

6)多用常量,少用顯式的"action_key",並維護一個常量類,別重復聲明這些常量。

7)如果可以,至少要弄懂設計模式中的策略模式,組合模式,裝飾模式,工廠模式,觀察者模式,這些能幫助你合理的解耦,即使需求頻繁變更,你也不用害怕牽一發而動全身。需求變更不可怕,可怕的是沒有在寫代碼之前做合理的設計。

8)View中設置緩存屬性.setDrawingCache為true.

9)cursor的使用。不過要注意管理好cursor,不要每次打開關閉cursor.因為打開關閉Cursor非常耗時。Cursor.require用於刷cursor.

10)採用SurfaceView在子線程刷新UI,避免手勢的處理和繪制在同一UI線程(普通View都這樣做)

11)採用JNI,將耗時間的處理放到c/c++層來處理

12)有些能用文件操作的,盡量採用文件操作,文件操作的速度比資料庫的操作要快10倍左右

13)懶載入和緩存機制。訪問網路的耗時操作啟動一個新線程來做,而不要再UI線程來做

14)如果方法用不到成員變數,可以把方法申明為static,性能會提高到15%到20%

15)避免使用getter/setter存取field,可以把field申明為public,直接訪問

16)私有內部類要訪問外部類的field或方法時,其成員變數不要用private,因為在編譯時會生成setter/getter,影響性能。可以把外部類的field或方法聲明為包訪問許可權

17)合理利用浮點數,浮點數比整型慢兩倍

18)針對ListView的性能優化,ListView的背景色與cacheColorHint設置相同顏色,可以提高滑動時的渲染性能。ListView中getView是性能是關鍵,這里要盡可能的優化。

getView方法中要重用view;getView方法中不能做復雜的邏輯計算,特別是資料庫操作,否則會嚴重影響滑動時的性能

19)不用new關鍵詞創建類的實例,用new關鍵詞創建類的實例時,構造函數鏈中的所有構造函數都會被自動調用。但如果一個對象實現了Cloneable介面,我們可以調用它的clone()方法。

clone()方法不會調用任何類構造函數。在使用設計模式(Design Pattern)的場合,如果用Factory模式創建對象,則改用clone()方法創建新的對象實例非常簡單。例如,下面是Factory模式的一個典型實現:

20)public static Credit getNewCredit() {
return new Credit();
}
改進後的代碼使用clone()方法,如下所示:
private static Credit BaseCredit = new Credit();
public static Credit getNewCredit() {
return (Credit) BaseCredit.clone();
}
上面的思路對於數組處理同樣很有用。

21)乘法和除法

考慮下面的代碼:

  • for (val = 0; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; }
    用移位操作替代乘法操作可以極大地提高性能。下面是修改後的代碼:
    for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }

  • 22)ViewPager同時緩存page數最好為最小值3,如果過多,那麼第一次顯示時,ViewPager所初始化的pager就會很多,這樣pager累積渲染耗時就會增多,看起來就卡。

    23)每個pager應該只在顯示時才載入網路或資料庫(UserVisibleHint=true),最好不要預載入數據,以免造成浪費

    24)提高下載速度:要控制好同時下載的最大任務數,同時給InputStream再包一層緩沖流會更快(如BufferedInputStream)

    25)提供載入速度:讓服務端提供不同解析度的圖片才是最好的解決方案。還有合理使用內存緩存,使用開源的框架

    引用:Android性能優化的淺談

    7. 多線程中 信號和信號量分別定義是什麼

    信號量在進程是以有名信號量進行通信的,在線程是以無名信號進行通信的,因為線程linux還沒有實現進程間的通信,所以在sem_init的第二個參數要為0,而且在多線程間的同步是可以通過有名信號量也可通過無名信號,但是一般情況線程的同步是無名信號量,無名信號量使用簡單,而且sem_t存儲在進程空間中,有名信號量必須LINUX內核管理,由內核結構struct ipc_ids 存儲,是隨內核持續的,系統關閉,信號量則刪除,當然也可以顯示刪除,通過系統調用刪除,
    消息隊列,信號量,內存共享,這幾個都是一樣的原理。,只不過信號量分為有名與無名

    8. android 大量多線程怎麼優化

    在程序開發的實踐當中,為了讓程序表現得更加流暢,我們肯定會需要使用到多線程來提升程序的並發執行性能。但是編寫多線程並發的代碼一直以來都是一個相對棘手的問題,所以想要獲得更佳的程序性能,我們非常有必要掌握多線程並發編程的基礎技能。
    眾所周知,Android 程序的大多數代碼操作都必須執行在主線程,例如系統事件(例如設備屏幕發生旋轉),輸入事件(例如用戶點擊滑動等),程序回調服務,UI 繪制以及鬧鍾事件等等。那麼我們在上述事件或者方法中插入的代碼也將執行在主線程。

    一旦我們在主線程裡面添加了操作復雜的代碼,這些代碼就很可能阻礙主線程去響應點擊/滑動事件,阻礙主線程的 UI 繪制等等。我們知道,為了讓屏幕的刷新幀率達到 60fps,我們需要確保 16ms 內完成單次刷新的操作。一旦我們在主線程裡面執行的任務過於繁重就可能導致接收到刷新信號的時候因為資源被佔用而無法完成這次刷新操作,這樣就會產生掉幀的現象,刷新幀率自然也就跟著下降了(一旦刷新幀率降到 20fps 左右,用戶就可以明顯感知到卡頓不流暢了)。

    為了避免上面提到的掉幀問題,我們需要使用多線程的技術方案,把那些操作復雜的任務移動到其他線程當中執行,這樣就不容易阻塞主線程的操作,也就減小了出現掉幀的可能性。

    那麼問題來了,為主線程減輕負的多線程方案有哪些呢?這些方案分別適合在什麼場景下使用?Android 系統為我們提供了若干組工具類來幫助解決這個問題。
    AsyncTask: 為 UI 線程與工作線程之間進行快速的切換提供一種簡單便捷的機制。適用於當下立即需要啟動,但是非同步執行的生命周期短暫的使用場景。
    HandlerThread: 為某些回調方法或者等待某些任務的執行設置一個專屬的線程,並提供線程任務的調度機制。
    ThreadPool: 把任務分解成不同的單元,分發到各個不同的線程上,進行同時並發處理。
    IntentService: 適合於執行由 UI 觸發的後台 Service 任務,並可以把後台任務執行的情況通過一定的機制反饋給 UI。
    了解這些系統提供的多線程工具類分別適合在什麼場景下,可以幫助我們選擇合適的解決方案,避免出現不可預期的麻煩。雖然使用多線程可以提高程序的並發量,但是我們需要特別注意因為引入多線程而可能伴隨而來的內存問題。舉個例子,在 Activity 內部定義的一個 AsyncTask,它屬於一個內部類,該類本身和外面的 Activity 是有引用關系的,如果 Activity 要銷毀的時候,AsyncTask 還仍然在運行,這會導致 Activity 沒有辦法完全釋放,從而引發內存泄漏。所以說,多線程是提升程序性能的有效手段之一,但是使用多線程卻需要十分謹慎小心,如果不了解背後的執行機制以及使用的注意事項,很可能引起嚴重的問題。

    9. 信號量,互斥鎖,讀寫鎖和條件變數的區別

    線程同步的方式包括:互斥鎖、讀寫鎖、條件變數、信號量和令牌。

    以Java語言為例:
    用synchronized關鍵字修飾同步方法。
    同步有幾種實現方法分別是synchronized,wait與notify
    wait():使一個線程處於等待狀態,並且釋放所持有的對象的lock。
    sleep():使一個正在運行的線程處於睡眠狀態,是一個靜態方法,調用此方法要捕捉InterruptedException異常。
    notify():喚醒一個處於等待狀態的線程,注意的是在調用此方法的時候,並不能確切的喚醒某一個等待狀態的線程,而是由JVM確定喚醒哪個線程,而且不是按優先順序。
    Allnotity():喚醒所有處入等待狀態的線程,注意並不是給所有喚醒線程一個對象的鎖,而是讓它們競爭。
    同步是多線程中的重要概念。同步的使用可以保證在多線程運行的環境中,程序不會產生設計之外的錯誤結果。同步的實現方式有兩種,同步方法和同步塊,這兩種方式都要用到synchronized關鍵字。

    閱讀全文

    與android線程信號量相關的資料

    熱點內容
    上汽榮威app在哪裡查詢 瀏覽:901
    冰櫃壓縮機溫度108 瀏覽:718
    阿里雲郵smtp伺服器地址 瀏覽:250
    解壓館認知理解 瀏覽:239
    為什麼使用非官方伺服器會封號 瀏覽:9
    佛山加密文檔軟體 瀏覽:813
    港式5張梭哈源碼 瀏覽:241
    數據中心pdf 瀏覽:524
    crf源碼解析 瀏覽:853
    伺服器軟體開發是什麼意思 瀏覽:941
    刪除彩信android 瀏覽:862
    元宵節猜燈謎h5源碼 瀏覽:69
    樂培生app怎麼綁定 瀏覽:762
    視頻壓縮不清楚怎麼說 瀏覽:525
    加好友伺服器繁忙是怎麼回事 瀏覽:381
    怎麼解綁app的支付寶賬號 瀏覽:913
    ip地址伺服器不可用怎麼解決方法 瀏覽:185
    為什麼軟體需要伺服器 瀏覽:65
    redis操作命令大全 瀏覽:599
    python字元串重復索引 瀏覽:964