之前分析了AsyncTask源代码,那么在使用AsyncTask的过程中,又存在什么问题呢?
AsyncTask使用存在的问题
AsyncTask在使用过程中,容易出像两个问题
其一:线程池容量不够,抛出异常java.util.concurrent.RejectedExecutionException
其二:内存泄漏
九以上两个问题,这里提出合理解决方案
线程池容量不够抛出
这里模拟出一个AsyncTask
的执行,然后看一看要怎么解决这个问题
public class AsyncTaskTest {
public static void main(String[] args) {
int CPU_COUNT = Runtime.getRuntime().availableProcessors(); //可用的CPU个数
int CORE_POOL_SIZE = CPU_COUNT + 1;
int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
int KEEP_ALIVE = 1;
//任务队列(128)
final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
//线程工厂
ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
String name = "Thread #" + mCount.getAndIncrement();
System.out.println(name);
return new Thread(r, name);
}
};
//线程池
Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
for (int i = 0; i < 200; i++) {
//相当于new AsyncTask().execute();
THREAD_POOL_EXECUTOR.execute(new MyTask());
}
}
static class MyTask implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
while(true){
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000); //使线程发生阻塞,模拟任务没有处理完成
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
一运行,就会产生java.util.concurrent.RejectedExecutionException
异常,这是由于分配的128容量不够导致的,那么该如何改进呢?
使用自定义的线程池就可以满足要求,在Android中的具体应用是这样的
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Executor exec = Executors.newScheduledThreadPool(25); //自定义线程池
for (int i = 0; i < 200; i++){
new MyTask().executeOnExecutor(exec);
}
}
class MyTask extends AsyncTask<Void, Integer, Void>{
@Override
protected Void doInBackground(Void... voids) {
return null;
}
}
内存泄露
当在AsyncTask中执行任务的时候,如果此时退出,那么其子线程不会被回收,其仍然持有Activity,这时候就会造成内存泄露,例如下面的例子
public class MainActivity extends AppCompatActivity {
private MyTask myTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTask = new MyTask();
myTask.execute();
}
@Override
protected void onDestroy() {
super.onDestroy();
myTask.cancel(true);
}
class MyTask extends AsyncTask<Void, Integer, Void>{
@Override
protected Void doInBackground(Void... voids) {
int count = 0;
while(true){
Log.d("cj5785",String.valueOf(count++));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}
}
此时如果这个活动被销毁,那么将会出现打印依旧继续的情况,这样也就造成了内存泄漏,这时候在doInBackground()
方法中使用判断,就可以避免这种情况发生
while(!isCancelled()){
Log.d("cj5785",String.valueOf(count++));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}