Android 개발-ExecutorService 를 통 해 앱 이 사용 하 는 전역 스 레 드 풀 구축
9513 단어 [Android 상용 개발]
프롤로그
구조 방법
스 레 드 탱크 운행 논리
사용자 정의 스 레 드 탱크스 레 드 탱크 닫 기
머리말
안 드 로 이 드 개발 에서 스 레 드 의 사용 은 틀림없이 없어 서 는 안 될 것 이다.왜냐하면 메 인 스 레 드 에 서 는 시간 을 소모 하 는 작업 을 할 수 없 기 때문이다.그러나 스 레 드 를 사용 해도 new Thrad 방식 으로 직접 사용 할 수 없습니다.목록 과 같은 페이지 는 불 러 와 야 할 그림 이 많 기 때문에 비동기 로 만 실행 할 수 있 습 니 다.new 를 직접 사용 하면 핸드폰 메모리 에 대한 압력 을 짐작 할 수 있 습 니 다.다행히 안 드 로 이 드 는 스 레 드 탱크 와 같은 것 을 제공 하여 스 레 드 를 관리 하 는 작업 을 제공 합 니 다.그런데 Android 는 우리 에 게 AsyncTask 와 같은 종 류 를 제공 해 주 었 습 니 다.내부 에 스 레 드 탱크 를 유지 하고 있 습 니 다.그러나 매우 아 픈 것 은 이 스 레 드 탱크 가 직렬 로 실행 되 고 병행 작업 을 할 수 없습니다.그러면 우 리 는 스스로 포장 할 수 밖 에 없습니다.
본 논문 에 포 함 된 코드 는 수시로 업데이트 되 며,여기에서 최신 코드 전송 문 을 다운로드 할 수 있다.
ThreadPoolExecutor
Android 에서 스 레 드 에 관 한 API 는 자바 의 조상 이 Executor 라 는 인터페이스 로 스 레 드 를 실행 하 는 방법 execute(Runnable command)를 제공 합 니 다.또 다른 인터페이스 Executor Service 는 Executor 를 계승 하여 능력 을 확장 시 켰 다.
항상 인 터 페 이 스 를 할 수 는 없 잖 아 요.누 군가 이런 개 세 무공 을 실현 해 야 죠.맞아요.바로 Thread PoolExecutor 라 는 손자 예요.
Executors
자바 가 Executors 류 를 제공 한 다 는 것 을 알 아야 한다.이 를 통 해 다양한 스 레 드 풀 을 구축 할 수 있다.
new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
이제 알 겠 습 니 다.Executors 류 는 공식 적 으로 개발 자 들 의 편 의 를 위해 스 레 드 탱크 를 봉인 한 것 입 니 다.그래서 자신의 APP 에 맞 는 스 레 드 탱크 를 만 들 려 면 스스로 스 레 드 탱크 를 밀봉 하 세 요.(사실 시간 지연 작업 은 ThreadPoolExecutor+Handler 를 통 해 할 수 있 습 니 다)
구조 방법
Thread PoolExecutor 는 네 개의 무 거 운 구조 방법 을 제공 합 니 다.
여기 서 매개 변수 가 가장 많은 구조 방법 을 예 로 들 어 안의 매개 변 수 를 설명 한다.
구조 방법 을 알 게 된 후,하나의 스 레 드 탱크 의 통용 운행 논 리 는 어떤 것 입 니까?즉,스 레 드 탱크 의 스 레 드 실행 논 리 는 무엇 입 니까?
우리 가 execute 방법 을 통 해 스 레 드 를 제출 한 후에 그 행방 은 다음 과 같다.(여기 서 핵심 스 레 드 수가 0 인 경우 제외)
4.567917.스 레 드 탱크 에서 실행 중인 스 레 드 수량 이 핵심 스 레 드 수량 을 초과 하지 않 았 을 때 바로 핵심 스 레 드 를 새로 만들어 임 무 를 수행 합 니 다
위의 이러한 지식 포 인 트 를 알 게 된 후에 우 리 는 우리 자신의 APP 수요 에 부합 되 는 스 레 드 풀 을 만 들 수 있다.
먼저 해 야 할 일 은 스 레 드 탱크 의 핵심 스 레 드 수량 과 최대 스 레 드 수량 을 확인 하 는 것 이다.
4.567917.핵심 스 레 드 수량:사실은 위의 스 레 드 탱크 운행 논 리 를 통 해 알 수 있 듯 이 스 레 드 탱크 에서 실행 중인 스 레 드 수량 이 핵심 스 레 드 수량 에 달 했 지만 work Queue 대기 열 은 0 에서 가득 차 있 고 핵심 스 레 드 가 실행 되 지 않 은 이 시간 동안 작업 을 수행 할 수 없습니다.모두 대기 열 에 저장 되 어 있 기 때문에 이것 은 매우 중요 합 니 다.원 하 는 병발 효 과 는 사실상 이 루 지 못 했다.그러나 핵심 스 레 드 수량 을 0 으로 설정 할 수 없습니다.그러면 대기 열 이 가득 차 야 비 핵심 스 레 드 를 열 어 임 무 를 수행 할 수 있 습 니 다.만약 당신 의 대기 열 길이 가 매우 크다 면 당신 을 기다 리 는 것 은 OOM 입 니 다.그래서 이 대열 의 길 이 는 반드시 설정 해 야 합 니 다4.567917.최대 스 레 드 수량:이 값 은 앱 에 얼마나 많은 병발 량 이 있 는 지 고려 해 야 합 니 다.예 를 들 어 한 화면 에 몇 개의 목록 을 표시 할 수 있 는 지또 하 나 는 handler 에 들 어가 스 레 드 탱크 가 거부 하 는 상황 에 대응 해 야 합 니 다.그러면 우 리 는 스 레 드 탱크 를 정의 할 수 있 습 니 다.다음 과 같 습 니 다.
/**
* @Description TODO( )
* @author cxy
* @Date 2018/11/14 17:22
*/
public class LocalThreadPools {
private static String TAG = LocalThreadPools.class.getSimpleName();
private static ExecutorService THREAD_POOL_EXECUTOR;
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT-1,4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2;
private static final int KEEP_ALIVE_SECONDS = 60;
private static final BlockingQueue sPoolWorkQueue = new LinkedBlockingQueue<>(8);
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "MangoTask #" + mCount.getAndIncrement());
}
};
private void initThreadPool() {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory,new RejectedHandler()){
@Override
public void execute(Runnable command) {
super.execute(command);
Log.e(TAG,"ActiveCount="+getActiveCount());
Log.e(TAG,"PoolSize="+getPoolSize());
Log.e(TAG,"Queue="+getQueue().size());
}
};
//
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
private class RejectedHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
//
Toast.makeText(mContext.get()," , ",Toast.LENGTH_SHORT).show();
}
}
private WeakReference mContext;
private static LocalThreadPools instance;
private LocalThreadPools(Context context){
mContext = new WeakReference<>(context);
initThreadPool();
}
public static LocalThreadPools getInstance(Context context){
if (instance == null) {
instance = new LocalThreadPools(context);
}
return instance;
}
public void execute(Runnable command){
THREAD_POOL_EXECUTOR.execute(command);
}
}
호출 방법 은 다음 과 같다.
LocalThreadPools.getInstance(this).execute(new Runnable() {
@Override
public void run() {
Log.e(TAG,"NAME="+Thread.currentThread().getName());
}
});
스 레 드 풀 닫 기
스 레 드 풀 을 만 드 는 방법 이 있 으 니 닫 을 수 있 습 니 다.다음 과 같 습 니 다.
/**
* interrupt ,
*
*
* @return
*/
public List shutdownNow(){
return THREAD_POOL_EXECUTOR.shutdownNow();
}
/**
*
*
*
*
*/
public void shutDown(){
THREAD_POOL_EXECUTOR.shutdown();
sPoolWorkQueue.clear();
}