Android之线程池ExecutorService

本文只是记录一些零碎的东西

如果你看过这篇加载网络图片的文章,本篇算是对上一个的一个完善吧

每次new 一个线程,不说你也会想到这么做的坏处:

1. 每次new Thread新建对象性能差。
2. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
3. 缺乏更多功能,如定时执行、定期执行、线程中断。

然后我们要使用Java里提供给我们的线程池,先看看在java里测试

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadPool {

	public static void main(String[] args) { 
//java.util.concurrent.ThreadPoolExecutor.ThreadPoolExecutor(int corePoolSize,
//	int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(5));
         
        for(int i=0;i<15;i++){
            MyTask myTask = new MyTask(i);
            executor.execute(myTask);
            System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
            executor.getQueue().size()+",已执行完的任务数目:"+executor.getCompletedTaskCount());
        }
        executor.shutdown();
// 上面是我们自己创建,以下是java 提供好线程池构造函数		
//创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程,线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
		ExecutorService executorService1 = Executors.newCachedThreadPool();
		executorService1.execute(new MyTask(100));
		// 固定五个线程来执行任务,可控制线程最大并发数,超出的线程会在队列中等待
		ExecutorService executorService2 = Executors.newFixedThreadPool(5);
		executorService2.execute(new MyTask(200));
		// 创建一个定长线程池,支持定时及周期性任务执行,延迟3秒执行
		ScheduledExecutorService scheduledThreadPool3 = Executors.newScheduledThreadPool(5);
		scheduledThreadPool3.schedule(new Runnable() {
		 
			@Override
			public void run() {
				System.out.println("delay 3 seconds");
			}
		}, 3, TimeUnit.SECONDS);
		// 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
		ExecutorService executorService4 = Executors.newSingleThreadExecutor(); 
		executorService4.execute(new MyTask(400));
		
    }
	
	
}
class MyTask implements Runnable {
	private int taskNum;
	
	public MyTask(int num) {
		this.taskNum = num;
	}
	
	@Override
	public void run() {
		System.out.println("正在执行task "+taskNum);
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("task "+taskNum+"执行完毕");
	}
};
更改上篇文章中的代码,需要注意的是多线程公用一个对象的问题,我一开始没有注意,三张图片只显示最后一张,原来是对象的全局的,三个线程都是操作的一个ImageView,看看工具类,实测有效

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
/**
 * 根据 url 获取用户头像
 * 
 * @author chenling0418
 * 
 */
public class UserImgHttp {

	private static Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
	private static Bitmap bitmap;
	private static Handler mHandler = new Handler();
	// 固定五个线程来执行任务
	private static ExecutorService executorService = Executors.newCachedThreadPool();
	private static ImageView view;//要显示图片的控件
	private static String url;//图片的网络地址
	private static int degree;//图片显示时相较原图旋转的角度,即图片旋转显示
	
	
	public static void setUserImg3(final ImageView view1,final String url1,final int degree1) {
		
		
		//从缓存中取软引用的Bitmap对象
		SoftReference<Bitmap> bitmapcache_ = imageCache.get(url1);
		bitmap = null;
		//取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
		if(bitmapcache_ != null){
			bitmap = bitmapcache_.get();
		}

		if(bitmap != null){
			Log.i("slack", "bitmap_ != null");
			changeView(mHandler,view1,bitmap);
		}else{
			view = view1;
			url = url1;
			degree = degree1;
//			Log.i("slack","url:"+url);

			executorService.execute(new GetWebPic(url1, view1,bitmap, degree1));
			

		}
		
		
	}

	
	
	private static void changeView(Handler handler,final ImageView view,final Bitmap bitmap) {

		handler.post(
        		new Runnable() {
					
					@Override
					public void run() {
						
						view.setImageBitmap( bitmap );
//						Log.i("slack", "img done...");
					}
				});
		
	}

	public static class GetWebPic  implements Runnable {
		
		private ImageView mImageView;
		private Bitmap mBitmap;
		private String mUrl;// url地址
		private int mDegree;// 旋转角度
		
		public GetWebPic(String url,ImageView imageView,Bitmap bitmap,int degree){
			this.mUrl = url;
			this.mImageView = imageView;
			this.mBitmap = bitmap;
			this.mDegree = degree;
		}
		
		@Override
		public void run() {
			InputStream inputStream = null;
			ByteArrayOutputStream out = null;
			try {
				
//				Log.i("slack", "img start..."+Thread.currentThread().getName()+mUrl);
				URL localURL = new URL(mUrl);
				
				URLConnection connection = localURL.openConnection();
				HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
				
				httpURLConnection.setRequestProperty("Accept-Charset", "utf-8");
				httpURLConnection.setRequestProperty("Content-Type",
						"application/x-www-form-urlencoded");
				
				if (httpURLConnection.getResponseCode() >= 300) {
					Log.i("slack","error:"+httpURLConnection.getResponseCode());
					throw new Exception(
							"HTTP Request is not success, Response code is "
									+ httpURLConnection.getResponseCode());
				}
				inputStream = httpURLConnection.getInputStream();
				
				out = new ByteArrayOutputStream();
				byte[] buffer=new byte[1024];
				int n=0;
				while ( (n=inputStream.read(buffer)) !=-1) {
					out.write(buffer,0,n);
				}
				//本地缓存图片
				out.close();
				//强引用的Bitmap对象
				mBitmap = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.toByteArray().length);
				
				Matrix matrix = new Matrix();
				matrix.setRotate(mDegree);
				int width = mBitmap.getWidth();
				int height = mBitmap.getHeight();
				mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width,
						height, matrix, true);
				
				//软引用的Bitmap对象
				SoftReference<Bitmap> bitmapcache = new SoftReference<Bitmap>(mBitmap);
				//添加该对象到Map中使其缓存
				imageCache.put(mUrl,bitmapcache);
				
				changeView(mHandler,mImageView,mBitmap);
				
				
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				Log.i("slack","error:"+e.toString());
			}finally{
				try {
					
					inputStream.close();
					out.close();
					
					
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
		}
	};
	
	
}



还有上面的缓存图片的方式,貌似更容易被垃圾回收器(GC)回收,使用LruCache,具体使用

/**
 * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
 */
private LruCache<String, Bitmap> mMemoryCache;

//获取应用程序最大可用内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 8;
// 设置图片缓存大小为程序最大可用内存的1/8
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key, Bitmap bitmap) {
        return bitmap.getByteCount();
    }
};
/**
 * 将一张图片存储到LruCache中。
 * 
 * @param key
 *            LruCache的键,这里传入图片的URL地址。
 * @param bitmap
 *            LruCache的键,这里传入从网络上下载的Bitmap对象。
 */
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
    if (getBitmapFromMemoryCache(key) == null) {
        mMemoryCache.put(key, bitmap);
    }
}

/**
 * 从LruCache中获取一张图片,如果不存在就返回null。
 * 
 * @param key
 *            LruCache的键,这里传入图片的URL地址。
 * @return 对应传入键的Bitmap对象,或者null。
 */
public Bitmap getBitmapFromMemoryCache(String key) {
    return mMemoryCache.get(key);
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值