性能优化之多线程优化

之前分析了AsyncTask源代码,那么在使用AsyncTask的过程中,又存在什么问题呢?

AsyncTask使用存在的问题

AsyncTask在使用过程中,容易出像两个问题
其一:线程池容量不够,抛出异常java.util.concurrent.RejectedExecutionException
其二:内存泄漏
九以上两个问题,这里提出合理解决方案

线程池容量不够抛出

这里模拟出一个AsyncTask的执行,然后看一看要怎么解决这个问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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中的具体应用是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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,这时候就会造成内存泄露,例如下面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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()方法中使用判断,就可以避免这种情况发生

1
2
3
4
5
6
7
8
while(!isCancelled()){
Log.d("cj5785",String.valueOf(count++));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Donate comment here