1. 程式人生 > 程式設計 >Android如何調整執行緒呼叫棧大小

Android如何調整執行緒呼叫棧大小

在常規的Android開發過程中,隨著業務邏輯越來越複雜,呼叫棧可能會越來越深,難免會遇到呼叫棧越界的情況,這種情況下,就需要調整執行緒棧的大小。

當然,主要還是增大執行緒棧大小,尤其是存在jni呼叫的情況下,C++層的棧開銷有時候是非常恐怖的,比如說遞迴呼叫。

這就需要分三種情況,主執行緒,自定義執行緒池,AsyncTask。

主執行緒的執行緒棧是沒有辦法進行修改的,這個沒辦法處理。

針對執行緒池的情況,需要在建立執行緒的時候,呼叫建構函式

public Thread(@RecentlyNullable ThreadGroup group,@RecentlyNullable Runnable target,@RecentlyNonNull String name,long stackSize)

通過設定stackSize引數來解決問題。

參考程式碼如下:

import android.support.annotation.NonNull;
import android.util.Log;

import java.util.concurrent.ThreadFactory;

/**
 * A ThreadFactory implementation which create new threads for the thread pool.
 */
public class SimpleThreadFactory implements ThreadFactory {
  private static final String TAG = "SimpleThreadFactory";
  private final static ThreadGroup group = new ThreadGroup("SimpleThreadFactoryGroup");
  // 工作執行緒堆疊大小調整為2MB
  private final static int workerStackSize = 2 * 1024 * 1024;

  @Override
  public Thread newThread(@NonNull final Runnable runnable) {
    final Thread thread = new Thread(group,runnable,"PoolWorkerThread",workerStackSize);
    // A exception handler is created to log the exception from threads
    thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
      @Override
      public void uncaughtException(@NonNull Thread thread,@NonNull Throwable ex) {
        Log.e(TAG,thread.getName() + " encountered an error: " + ex.getMessage());
      }
    });

    return thread;
  }
}
import android.support.annotation.AnyThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * A Singleton thread pool
 */
public class ThreadPool {
  private static final String TAG = "ThreadPool";
  private static final int KEEP_ALIVE_TIME = 1;
  private static volatile ThreadPool sInstance = null;
  private static int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
  private final ExecutorService mExecutor;
  private final BlockingQueue<Runnable> mTaskQueue;

  // Made constructor private to avoid the class being initiated from outside
  private ThreadPool() {
    // initialize a queue for the thread pool. New tasks will be added to this queue
    mTaskQueue = new LinkedBlockingQueue<>();

    Log.d(TAG,"Available cores: " + NUMBER_OF_CORES);

    mExecutor = new ThreadPoolExecutor(NUMBER_OF_CORES,NUMBER_OF_CORES * 2,KEEP_ALIVE_TIME,TimeUnit.SECONDS,mTaskQueue,new SimpleThreadFactory());
  }

  @NonNull
  @AnyThread
  public static ThreadPool getInstance() {
    if (null == sInstance) {
      synchronized (ThreadPool.class) {
        if (null == sInstance) {
          sInstance = new ThreadPool();
        }
      }
    }
    return sInstance;
  }

  private boolean isThreadPoolAlive() {
    return (null != mExecutor) && !mExecutor.isTerminated() && !mExecutor.isShutdown();
  }

  @Nullable
  @AnyThread
  public <T> Future<T> submitCallable(@NonNull final Callable<T> c) {
    synchronized (this) {
      if (isThreadPoolAlive()) {
        return mExecutor.submit(c);
      }
    }
    return null;
  }

  @Nullable
  @AnyThread
  public Future<?> submitRunnable(@NonNull final Runnable r) {
    synchronized (this) {
      if (isThreadPoolAlive()) {
        return mExecutor.submit(r);
      }
    }
    return null;
  }

  /* Remove all tasks in the queue and stop all running threads
   */
  @AnyThread
  public void shutdownNow() {
    synchronized (this) {
      mTaskQueue.clear();
      if ((!mExecutor.isShutdown()) && (!mExecutor.isTerminated())) {
        mExecutor.shutdownNow();
      }
    }
  }
}

針對AsyncTask的情況,一般是通過呼叫

public final AsyncTask<Params,Progress,Result> executeOnExecutor(Executor exec,Params... params)

指定執行緒池來執行,在特定的執行緒池中調整執行緒棧的大小。

參考程式碼如下:

import android.os.AsyncTask;
import android.support.annotation.AnyThread;
import android.support.annotation.NonNull;
import android.util.Log;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public abstract class AsyncTaskEx<Params,Result> extends AsyncTask<Params,Result> {

  private static final String TAG = "AsyncTaskEx";
  private static final int KEEP_ALIVE_TIME = 1;
  private static volatile ThreadPool sInstance = null;
  private static int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
  private final ExecutorService mExecutor;
  private final BlockingQueue<Runnable> mTaskQueue;

  public AsyncTaskEx() {
    // initialize a queue for the thread pool. New tasks will be added to this queue
    mTaskQueue = new LinkedBlockingQueue<>();

    Log.d(TAG,new SimpleThreadFactory());
  }

  public AsyncTask<Params,Result> executeAsync(@NonNull final Params... params) {
    return super.executeOnExecutor(mExecutor,params);
  }

  /* Remove all tasks in the queue and stop all running threads
   */
  @AnyThread
  public void shutdownNow() {
    synchronized (this) {
      mTaskQueue.clear();
      if ((!mExecutor.isShutdown()) && (!mExecutor.isTerminated())) {
        mExecutor.shutdownNow();
      }
    }
  }
}

參考連結

  • Increase AsyncTask stack size?
  • StackOverFlowError: Stack size 1036KB in AsyncTask
  • Android:增加呼叫堆疊大小
  • AsyncTask和執行緒池

以上就是Android如何調整執行緒呼叫棧大小的詳細內容,更多關於Android 調整呼叫棧大小的資料請關注我們其它相關文章!