zoukankan      html  css  js  c++  java
  • 性能优化-多线程优化

    之前分析了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();
        }
    }
    
  • 相关阅读:
    Javascript Property Names
    Java泛型
    Activity 与 Task
    使用ddns搭建免费服务器
    DDNS
    SimpleAdapter用法
    Java KeyNote
    Android无法访问本地服务器(localhost/127.0.0.1)的解决方案
    Android 添加网络权限
    Java 匿名内部类
  • 原文地址:https://www.cnblogs.com/cj5785/p/10664632.html
Copyright © 2011-2022 走看看