性能优化-多线程优化

之前分析了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();
    }
}
posted @ 2019-04-06 21:03  cj5785  阅读(182)  评论(0编辑  收藏  举报