android多執行緒併發協調semaphore機制
阿新 • • 發佈:2019-01-22
在專案開發過程中我們難免用到多執行緒機制,但不可否認的是如果對公共資源共同訪問時候沒有處理好執行緒同步的話很容易出現非執行緒安全的問題,會帶來不可預知的錯誤,在java中進行執行緒同步的話一般都用wait和notify機制,但個人認為有點難控制,其實我們用java提供的訊號量semaphore機制來處理執行緒同步的問題,接下來請看看程式碼:
首先講講大概流程,首先建立了輪詢執行緒,通過傳送handler方式去通知執行緒池執行任務,模擬一種多執行緒通訊,其中注意的是在addTask方法中必須加上鎖的機制synchronized,避免多執行緒訪問會引發問題,由於addTask方法與輪詢執行緒是併發的,誰也不知道誰先發生,所以addTask方法裡面必須對輪詢執行緒的handler進行判斷,如果為null則去申請一個訊號量,此時主執行緒會一直等待,然後如果輪詢執行緒裡handler初始化完畢則釋放訊號量,喚醒主執行緒向下執行。有人可能會說把addTask方法放在輪詢執行緒start方法下面執行不就行了嗎,其實不是這樣的,無論addTask方法線上程下面還是上面都不能保證執行addTask方法之前handler已經初始化完成了。package com.example.textdemo; import java.util.LinkedList; import java.util.UUID; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import android.support.v7.app.ActionBarActivity; import android.text.format.Time; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.SystemClock; public class MainActivity extends ActionBarActivity { private Thread mThread; private Handler threadHandler; LinkedList mTasks=new LinkedList(); //初始化執行緒池預設3個執行緒 ExecutorService mThreadPool=Executors.newFixedThreadPool(3); //初始化訊號量預設0 private Semaphore mThreadPoolSemaphore=new Semaphore(0); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); addTast(new Runnable() { @Override public void run() { // 模擬耗時任務 SystemClock.sleep(3000); } }); //開啟一個輪詢執行緒 mThread=new Thread(){ @Override public void run() { super.run(); Looper.prepare(); threadHandler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); //執行緒池執行任務 mThreadPool.execute(mTasks.removeFirst()); } }; //輪詢執行緒的Handler初始化完畢則釋放一個訊號量 mThreadPoolSemaphore.release(); Looper.loop(); } }; mThread.start(); } synchronized private void addTast(Runnable runnable) { //插入執行緒佇列 mTasks.add(runnable); if(threadHandler==null){//須要判斷此時輪詢執行緒Handler是否null try { //申請訊號量,執行緒阻塞等待 mThreadPoolSemaphore.acquire(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //輪詢執行緒通知執行緒池執行任務 threadHandler.sendEmptyMessage(0); } }