android开发系列之多线程
? ? ? 今天在這篇博客里面,我只想談談自己對程序開發里面避無可避的一個問題-多線程的一些看法與思考。
? ? ? 其實說到多線程這個名稱相信只要接觸過軟件這個行業的人都已經耳熟能詳了,但是如果被問到到底什么才是多線程呢?為什么我們會需要多線程呢?多線程又會造成什么副作用呢?其實這些都應該是值得我們深入思考的一些問題,因為在多線程的環境里面,往往會發生一些意想不到的事情。下面讓我們來針對android平臺來具體看看多線程應該是怎么一回事呢?其實在android里面,系統已經為我們提供了一些封裝好的多線程api,比如runable接口,AsyncTask后臺任務等。
? ? ? 讓我們先來看看一段代碼,這段代碼是比較常規的創建、開啟一個線程的方法。
public class TestThread extends Thread {@Overridepublic void run() {//do your something} }?上面方法只是定義好了一個線程,然后我們應該調用下面的方法運營它。
private void runMyThread(){new TestThread().start(); }?這樣的話,我們就相當于已經開啟了一個線程。所以只要不手動中斷這個線程的話,那么該線程就會在App處于運行態時一直跑。所以這個時候,如果我們有什么比較耗時的操作的話,我們就可以放在run方法里面執行了。下面就讓我們來看看Thread里面的源碼,看看為什么Thread調用start方法就會運行,為什么每個線程開啟之后都會循環執行里面的run方法呢?有沒有什么辦法去中斷一個線程呢?
? ? ? 首先我們來看看Thread的類定義,如下:
public class Thread implements Runnable{ }?可以看到Thread其實也是從Runable繼承而來,那么什么是Runable呢?讓我們稍后講。一進到Thread類定義里面,給我們最直觀的感受就是“volatile”,“ThreadLocal”,還有各種的Thread構造方法。我們可以看到在每個Thread構造方法里面都調用了create方法,相信看到這個名字大家就應該能夠知道它是干什么用的吧,讓我們截出create的源碼來看看:
private void create(ThreadGroup group, Runnable runnable, String threadName, long stackSize) {Thread currentThread = Thread.currentThread();if (group == null) {group = currentThread.getThreadGroup();}if (group.isDestroyed()) {throw new IllegalThreadStateException("Group already destroyed");}this.group = group;synchronized (Thread.class) {id = ++Thread.count;}if (threadName == null) {this.name = "Thread-" + id;} else {this.name = threadName;}this.target = runnable;this.stackSize = stackSize;this.priority = currentThread.getPriority();this.contextClassLoader = currentThread.contextClassLoader;// Transfer over InheritableThreadLocals.if (currentThread.inheritableValues != null) {inheritableValues = new ThreadLocal.Values(currentThread.inheritableValues);}// add ourselves to our ThreadGroup of choicethis.group.addThread(this);}從上面的源碼我們可以很清楚的看到create方法里面就是設置線程所屬的ThreadGroup,ThreadName,StackSize,但是有一點需要特別注意就是Runable對象,它是用來干什么的呢?我們通過代碼查找,發現它主要是用在run方法里面,代碼如下:
public void run() {if (target != null) {target.run();}}?我們可以看到Thread里面的run方法,其實是調用了Runable里面的方法。也就是說你可以在Thread實例化的時候,傳進來一個Runable對象,這個時候就能執行到里面的run方法了。但是別急,如果你以為這樣就能夠真正創建一個線程的話,那么就錯了。我們可以再看看start方法,也許你就能夠明白了。
public synchronized void start() {checkNotStarted();hasBeenStarted = true;nativeCreate(this, stackSize, daemon);}private native static void nativeCreate(Thread t, long stackSize, boolean daemon);?看到了嗎?其實在nativeCreate方法里面才會利用create方法里面設置的參數進行真正進行創建過程。現在讓我們回到原來那個問題上,為什么線程創建之后,會一直執行run方法呢?具體怎么循環調用的,我在源碼里面沒有找到,也許是在c層調的吧。然后我們還可以看到常用的sleep方法,源碼如下:
public static void sleep(long millis, int nanos) throws InterruptedException {if (millis < 0) {throw new IllegalArgumentException("millis < 0: " + millis);}if (nanos < 0) {throw new IllegalArgumentException("nanos < 0: " + nanos);}if (nanos > 999999) {throw new IllegalArgumentException("nanos > 999999: " + nanos);}// The JLS 3rd edition, section 17.9 says: "...sleep for zero// time...need not have observable effects."if (millis == 0 && nanos == 0) {// ...but we still have to handle being interrupted.if (Thread.interrupted()) {throw new InterruptedException();}return;}long start = System.nanoTime();long duration = (millis * NANOS_PER_MILLI) + nanos;Object lock = currentThread().lock;// Wait may return early, so loop until sleep duration passes.synchronized (lock) {while (true) {sleep(lock, millis, nanos);long now = System.nanoTime();long elapsed = now - start;if (elapsed >= duration) {break;}duration -= elapsed;start = now;millis = duration / NANOS_PER_MILLI;nanos = (int) (duration % NANOS_PER_MILLI);}}}?我們可以看到在java這層只是做了一些時間上面的預設判斷,真正的sleep實現是調用c層代碼:
private static native void sleep(Object lock, long millis, int nanos);?最后讓我們再來看看線程中斷的方法:
public void interrupt() {// Interrupt this thread before running actions so that other// threads that observe the interrupt as a result of an action// will see that this thread is in the interrupted state.nativeInterrupt();synchronized (interruptActions) {for (int i = interruptActions.size() - 1; i >= 0; i--) {interruptActions.get(i).run();}}}private native void nativeInterrupt();?看到上面的代碼其實有一點不解的就是,是不是意味著我中斷當前的一個線程,系統就會默認啟動后一個線程呢?
? ? ? ?好了,接下來我們可以再看看Runable,其實可以發現它就是一個接口,里面提供了一個run方法,代碼如下:
public interface Runnable {/*** Starts executing the active part of the class' code. This method is* called when a thread is started that has been created with a class which* implements {@code Runnable}.*/public void run(); }? ? ? 最后我們來看看AsyncTask方法,它的特點是什么?我們應該怎么來使用它呢?首先我們來看看在android代碼里面通常的使用方法是:
public class TestAsyncTask extends AsyncTask<String,Object,String> {@Overrideprotected String doInBackground(String... params) {return null;}@Overrideprotected void onPostExecute(String s) {super.onPostExecute(s);}@Overrideprotected void onProgressUpdate(Object... values) {super.onProgressUpdate(values);} }?定義一個類,然后繼承AsyncTask復寫里面的三個方法。下面就讓我們來具體看看AsyncTask的類定義:
public abstract class AsyncTask<Params, Progress, Result> { }?我們可以看到AsyncTask是一個抽象類,同時利用泛型的方式定義三個參數,分別代表傳入的參數、執行過程的進度、執行之后的結果。那么在AsyncTask里面又是怎樣調用doInBackground方法的呢?這就要回想一下,當我們定義好一個AsyncTask的時候,是怎樣運行它的呢?代碼如下:
private void testMyAsyncTask(){new TestAsyncTask().execute(url); }?所以我們只要看看execute方法里面是不是有調用就知道了。
@MainThreadpublic final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params... params) {if (mStatus != Status.PENDING) {switch (mStatus) {case RUNNING:throw new IllegalStateException("Cannot execute task:"+ " the task is already running.");case FINISHED:throw new IllegalStateException("Cannot execute task:"+ " the task has already been executed "+ "(a task can be executed only once)");}}mStatus = Status.RUNNING;onPreExecute();mWorker.mParams = params;exec.execute(mFuture);return this;}?最終它會調用到上面的方法實現我們復寫的三個方法實現。
? ? ? ?好了,這篇博客就到這里。理解不夠深入、不到的地方,歡迎拍磚!
?
轉載于:https://www.cnblogs.com/xiaocai20091687/p/android-xiaocai-thread.html
總結
以上是生活随笔為你收集整理的android开发系列之多线程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Vijos p1165 火烧赤壁 离散化
- 下一篇: 注释(Annotation)