JAVA中的Executors使用
来源:互联网 发布:mac好玩的免费游戏 编辑:程序博客网 时间:2024/05/14 12:24
一 . Java通过Executors提供四种线程池
1 . newCachedThreadPool :创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。private void notWorkCachedThread() { ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; try { Thread.sleep(index * 1000); } catch (InterruptedException e) { e.printStackTrace(); } cachedThreadPool.execute(new Runnable() { public void run() { System.out.println(index); } }); }}
2 . newFixedThreadPool : 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
private void notWorkFixedThread(){ ExecutorService fixedThreadPool = Executors.newFixedThreadPool( 3 ); for (int i = 0; i < 10; i++) { final int index = i; fixedThreadPool.execute(new Runnable() { public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); }}因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()
3 . newScheduledThreadPool : 创建一个定长线程池,支持定时及周期性任务执行。
public void notWorkScheduledThread(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.schedule(new Runnable() { public void run() { System.out.println("delay 3 seconds"); } }, 3, TimeUnit.SECONDS);//表示延迟3秒执行}
public void notWorkScheduledThread2(String[] args) { ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println("delay 1 seconds, and excute every 3 seconds"); } }, 1, 3, TimeUnit.SECONDS); //表示延迟1秒后每3秒执行一次}
4 . newSingleThreadExecutor :创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
public static void notWorkSingleThreadExecutor(String[] args) { ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int index = i; singleThreadExecutor.execute(new Runnable() { public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }); }}结果依次输出,相当于顺序执行各个任务。
二 . LruCachec缓存
在Android中,有一个叫做LruCache类专门用来做图片缓存处理的。它有一个特点,当缓存的图片达到了预先设定的值的时候,那么近期使用次数最少的图片就会被回收掉。LruCache里面的键值对分别是URL和对应的图片。
看代码:
public class MemoryCache extends LruCache< String ,Bitmap > { /** * @param maxSize for caches that do not override {@link #sizeOf}, this is * the maximum number of entries in the cache. For all other caches, * this is the maximum sum of the sizes of the entries in this cache. * //1.如果重写sizeOf方法的话,构造函数中maxsize的值代表的是缓存中对象所占用的内存总量 * //2.如果不重写sizeOf方法的话,构造函数中maxSize的值代表的是缓存中的对象个数 * 手机内存的获取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024); */ public MemoryCache(int maxSize) { super(maxSize); } @Override protected int sizeOf( String key , Bitmap value ) { return value.getByteCount(); }}
学习了 java 中的Executors 和Android中的LruCache,接下来我来写一个简单网络框架。
网络请求不外乎就是请求图片和请求字符串。
看代码:
public abstract class Request< A > { //接口对象 private Callback mCallback; //网址 private String url; //请求方式 private Method method; //枚举成员 public enum Method { GET, PSOT } /** * 构造方法 */ public Request(String url, Method method, Callback callback) { this.url = url; this.method = method; mCallback = callback; } /** * 属性封装方法 * @return */ public String getUrl() { return url; } public void setUrl(String url) { this.url = url ; } public Method getMethod() { return method ; } public void setMethod( Method method ) { this.method = method ; } /** * 返回接口对象 * @return */ public Callback getCallback() { return mCallback ; } /** * 接口 * 有一个泛型 T 作为 onSucess方法参数的类型 */ public interface Callback<T> { //两个抽象方法 void onSucess(T data); void onError(Exception exception); } /** * 抽象方法 * 发起网络请求 URL 链接后请求下来的是字节数组 把自己数组传进去返回一个A * 用户象要发起网络请求时,就要根据url 和自己的想要请求方式创建一个Request对象, * 然后重写这个反方,在创建这个对象时 ,指定一个泛型 最后在重写这个方法的时候就对字节数组进行处理返回这个类的对象 * 返回一个泛型 A * @param data * @return */ abstract public A parseNetworkResponse(byte[] data); /** * (这个方法在网络数据请求下来后(bayt数组)调用这个方法) * 把字节数组转化成 A 泛型的类型 。 * 在调用接口的方法(方法的参数的类型的是泛型的 A 把 a 传进去 ) * 用户在创建接口对象时必须要成写接口的两个方法 * 所以 mCallback.onSucess(a);执行的代码是用户端冲写的方法里面的代码 * 这样我们就可以对 a 进行处理了 。 * @param data */ public void dispatchResult( byte[] data ) { A a = parseNetworkResponse( data ) ; mCallback.onSucess( a ) ; } /** * 这个方法主要用来post请求的时候 * 用户端发起请求的时候 如果是post请求就要重写这个方法(因为这里返回的是null) * map集合里面装得是请求的参数 * 我们重写这个方法后 ,就可以返回我们想要请求的参数的map集合 * @return */ public Map<String , String> getPostParams() { return null ; }}抽象Request类是对请求参数的封装。里面有Url , 请求方式 , 数据请求下来后回调的接口,有一个抽象方法。请求有IamgerRequest请求,StringRequest请求。这个抽象方法的作用在后面说明。(这里使用的是java中的策略模式思想)。
参数有了,就链接网络了,网络请求的耗时任务必须放在工作线程中,所以请求的代码应该写在Runnable 的run方法中。
看代码:
public class NetWorkRunnable implements Runnable{ private static final int OUTTIEM = 5000 ; private Request request ; //自写的一个类,封装请求参数的一个类,里面有url ,请求的方式 ,和数据请求下来后回调的接口 /** * 构造方法 * request 此次请求的参数封装在这个类中。 */ public NetWorkRunnable( Request request ){ this.request = request ; } /** * 根据请求参数类取请求方式 * @param method * @return */ public static String getStringMethod( Request.Method method ){ if (method == Request.Method.GET) return "GET"; if (method == Request.Method.PSOT) return "POST"; //默认返回GET请求 return "GET" ; } @Override public void run() { InputStream is = null ; try { URL url = new URL( request.getUrl() ) ; HttpURLConnection connt = ( HttpURLConnection) url.openConnection() ; connt.setRequestMethod( getStringMethod( request.getMethod())) ; //设置请求的方式 connt.setConnectTimeout( OUTTIEM ) ; //设置连接的超时时间 if( request.getMethod() == Request.Method.PSOT ){//判断是否是post请求 //允许写出(默认为false) connt.setDoOutput( true ) ; //设置允许允许输出 //获取输出流 OutputStream out = connt.getOutputStream() ; //遍历map集合(找出请求的参数) HashMap<String,String> params = (HashMap<String , String>) request.getPostParams() ; String postParsms = "" ; //获取迭代器 Iterator<Map.Entry< String , String >> iterator = params.entrySet().iterator() ; //遍历map集合(找出请求的参数) while ( iterator.hasNext() ){ Map.Entry<String,String> entry = iterator.next() ; String temp = entry.getKey()+"="+entry.getValue() ; postParsms += temp+ "&" ; } //去掉最后一个字符 postParsms = postParsms.substring( 0 , postParsms.length() - 1 ) ; out.write( postParsms.getBytes() ) ;//发送参数 //一定要刷新一下 out.flush() ; } //链接 connt.connect() ; if( connt.getResponseCode() == HttpURLConnection.HTTP_OK ){ int len = -1 ; byte[] buf = new byte[1024] ; is = connt.getInputStream() ; ByteArrayOutputStream baos = new ByteArrayOutputStream() ; while ( (len = is.read(buf))!=-1 ){ baos.write( buf ,0 ,len ) ; } //关键是请求数据下来后要怎样的处理( 调用request对象的dispatchResult()) request.dispatchResult( baos.toByteArray() ) ; //回调 } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if ( is != null ){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } } }}
用到接口回调的思想,数据请求下来后,进行回调在
request.dispatchResult( baos.toByteArray() ) ;
图片请求时 ,看代码:
public class ImageRequest extends Request <Bitmap> { /** * 构造方法 * @param url * @param method * @param callback */ public ImageRequest(String url, Method method, Callback callback) { super(url, method, callback) ; } @Override public Bitmap parseNetworkResponse(byte[] data) { /** * 文件目录 * 这个文件的目录在终极类里面,初始化终极类的时候就初始化了这个目录 */ String cacheDir = HttpUltimate.CACHE_DIR ; /** *这里是把图片缓存到内存中去 */ if ( cacheDir != null ){ String fileName = getFileName( getUrl() ) ; //Request类有getUrl()方法( 所以可以直接使用 ) File file = new File( cacheDir + "/" + fileName ) ; try { //把图片写到磁盘上 FileOutputStream fos = new FileOutputStream( file ) ; fos.write( data , 0 ,data.length ) ; fos.flush() ; fos.close() ; } catch (FileNotFoundException e) { e.printStackTrace() ; } catch (IOException e) { e.printStackTrace() ; } } //创建bitmap位图 Bitmap bm = BitmapFactory.decodeByteArray( data , 0 , data.length ); return bm ; } /** * 把url字符串转换成可以用来命名文件名的字符串 * @return */ public static String getFileName( String url){ String fileName = url.replace("/" , "-").replace(":" ,"-").replace("?" ,"-") ; return fileName; }}
字符串数据请求时:
public class StringRequest extends Request< String > { /** * 构造方法 * @param url * @param method * @param callback */ public StringRequest( String url , Method method , Callback callback ) { super( url , method , callback ) ; } /** * 重写的抽象方法 * @param data * @return */ @Override public String parseNetworkResponse( byte[] data ) { return new String( data ) ; }}
看完这两个类应该知道这个抽象方法的作用了吧。体现了策略模式的编程思想。
使用到Executors和lruCache缓存缓存图片
看代码:
public class CoreHttp { //线程池对象 private ExecutorService mThreadPool ; /** * 构造方法 ,创建线程池实体 * @param context */ public CoreHttp( Context context ) { //创建线程池对象(固定大小的线程池) mThreadPool = Executors.newFixedThreadPool( 3 ) ; } /** * 发起网络请求的方法 * @param ( 参数是个请求类对象 包含请求的网址,和请求方式,还有回调的接口对象 ) */ public void sendRequest( Request request ){ //往线程池塞任务 mThreadPool.submit( new NetWorkRunnable( request ) ) ; }}lruCache缓存:
public class MemoryCache extends LruCache< String ,Bitmap > { /** * @param maxSize for caches that do not override {@link #sizeOf}, this is * the maximum number of entries in the cache. For all other caches, * this is the maximum sum of the sizes of the entries in this cache. * //1.如果重写sizeOf方法的话,构造函数中maxsize的值代表的是缓存中对象所占用的内存总量 * //2.如果不重写sizeOf方法的话,构造函数中maxSize的值代表的是缓存中的对象个数 * 手机内存的获取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 1024); */ public MemoryCache(int maxSize) { super(maxSize); } @Override protected int sizeOf( String key , Bitmap value ) { return value.getByteCount(); }}
工具准备好了就要使用了,先看图片的请求:
public class IamgeLoader { //含有线程池类的对象 private CoreHttp mCoreHttp ; //图片加载对象 private static IamgeLoader iamgeLoader ; //缓存对象 private MemoryCache mMemoryCache ; /** * 构造方法 */ private IamgeLoader( Context context ){ //线程对象也有了 mCoreHttp = new CoreHttp( context ) ; //因为重写了 mMemoryCache = new MemoryCache( 1024 * 1024 * 10 ); //10M } /** * 加载图片 * 1 . 先从缓存读取 * 2 . 没有 , 在从磁盘度取 * 3 . 还是没有 , 再走网络 * * @param url * * @param imageView * */ public static void loadImage( final String url , final ImageView imageView ){ //设置标记 imageView.setTag( url ) ; /** * 首先读取LruCache缓存 */ Bitmap bm = iamgeLoader.mMemoryCache.get( url ) ; //因为MemoryCache继承LruCache, key是url , Object 是bitmap if ( bm != null ){ imageView.setImageBitmap( bm ) ; return ; } /** *没有 , 在读取本地(磁盘) */ String fileName = ImageRequest.getFileName( url ) ; bm = getBitmapFromLocalCache( fileName ) ; if( bm != null ){ imageView.setImageBitmap( bm ) ; //添加到lruach缓存中去 iamgeLoader.mMemoryCache.put( url , bm ) ; } /** *还是没有 再图片请求 */ ImageRequest imgRequest = new ImageRequest( url , Request.Method.GET , new Request.Callback< Bitmap >() { @Override public void onSucess( final Bitmap data ) { iamgeLoader.mMemoryCache.put( url , data ) ; if( imageView.getTag().toString().equals( url )){ //一定要在主线程更新UI HttpUltimate.handler.post( new Runnable() { @Override public void run() { imageView.setImageBitmap( data ) ; } }) ; } } @Override public void onError( Exception exception) { } }) ; /** * 发起网络请求 发起网络请求 */ iamgeLoader.mCoreHttp.sendRequest( imgRequest ) ; } /** * 获取实例 * @param context * @return */ public static void initImageLoader(Context context){ if ( iamgeLoader == null ){ synchronized ( IamgeLoader.class ){ if ( iamgeLoader == null ){ /** * new之后 网络请求的核心类有了 mCoreHttp 实例了 * mMemoryCache 缓存也有实例了 */ iamgeLoader = new IamgeLoader( context ); } } } return ; } /** * 从本地读取图片 * @param filename * @return */ private static Bitmap getBitmapFromLocalCache( String filename ){ File file = new File( HttpUltimate.CACHE_DIR + "/" + filename ) ; if (!file.exists()){ return null ; } return BitmapFactory.decodeFile(filename); }}再看字符串请求
public class HttpLoader { private CoreHttp mCoreHttp ; private static HttpLoader httpLoader ; /** * 构造方法 * @param context */ private HttpLoader( Context context ){ //创建这个对象后,线城池也就常见好了 mCoreHttp = new CoreHttp( context ) ; } /** * 创建本类实例 * @param context */ public static void initHttpLoader( Context context ){ if( httpLoader == null ){ synchronized ( HttpLoader.class ){ if ( httpLoader == null ){ httpLoader = new HttpLoader( context ) ; } } } } /** * 加载网络数据 * @param request */ public static void loadData( Request request ){ //为什么使用httpLoader. 调用静态方法中不能使用非静态变量 httpLoader.mCoreHttp.sendRequest( request ) ; }}
最后的封装,看代码:
public class HttpUltimate { //绑定主线程的Looper的Handler对象 public static Handler handler ; //这是个终极类 //1.可以加载图片 //2.可以进行网络数据的访问 //缓存文件的目录 public static String CACHE_DIR ; /** * 初始化实例 * 图片加载实例 * 网络数据加载实例 * 还有初始化缓存目录 * @param context */ public static void intiHttpUltimate( Context context ){ //加载网路数据 HttpLoader.initHttpLoader( context ) ; //加载图片数据 IamgeLoader.initImageLoader( context ) ; //初始化缓存的目录 CACHE_DIR = getCachePath( context ) ; //初始handler对象 handler = new Handler() ; } /** * 加载图片的静态的方法 * @param url * @param imageView */ public static void loadIamge( String url , ImageView imageView ){ IamgeLoader.loadImage( url , imageView ) ; } /** * 加载网络数据的静态的方法 * @param request */ public static void loadData( Request request ){ HttpLoader.loadData( request ) ; } /** * 初始化缓存目录 */ public static String getCachePath( Context context ){ //获取data/data/应用程序包名/Cache目录 File file = new File( context.getCacheDir().getAbsolutePath() + "/img" ); //文件夹不存在就不要创建文件夹 if (!file.exists()){ file.mkdirs() ; } return file.getAbsolutePath() ; //返回文件的绝对路径 }}
现在是真正的把工具类准备好了,接下来就是使用了,看代码:
public class BaiKeApplication extends Application { @Override public void onCreate() { super.onCreate(); //初始化终极类 HttpUltimate.intiHttpUltimate( getApplicationContext() ); }}先初始化。
//链接URLString url = AppGlobal.ROOT_URL + imgPath ;//加载图片HttpUltimate.loadIamge( url,imageIv ) ;加载图片。
/** * 网络加载数据 */private void loadFromNetwork() { //创建字符串请求对象 StringRequest sr = new StringRequest( rooturl + id , Request.Method.GET , new Callback< String >(){ @Override public void onSucess(String data) { try { JSONObject json = new JSONObject(data) ; final String description = json.getString("description") ; final String keywords = json.getString("keywords") ; final String img = json.getString("img") ; final String message = json.getString("message") ; food = new HealthFood( description , keywords , id , img ) ; Log.d("page" , " food 数据已经请求下来") ; list = fdb.findItme( HistoryTable.history_flag , HistoryTable.id_column+"=? and " + HistoryTable.img_column + "=?" , new String[]{ id+"" , img }); if( list == null || list.size() == 0 ){ fdb.add( food , HistoryTable.history_flag ) ; } //添加到浏览历史列表 HttpUltimate.handler.post( new Runnable() { @Override public void run() { fillView( description , keywords , img , message ) ; Log.d("page" , " UI 更新成功") ; } }) ; } catch (JSONException e) { e.printStackTrace(); } } @Override public void onError(Exception exception) { } }) ; //加载网络数据 HttpUltimate.loadData( sr ); Log.d("page" , " 发起网络请求了") ;请求字符串。
写得不好,请多多指教!
- JAVA中的Executors使用
- 使用Executors
- Java:使用Executors创建和管理线程
- Java:使用Executors创建和管理线程
- Java:使用Executors创建和管理线程
- Java:使用Executors创建和管理线程
- Java:使用Executors创建和管理线程
- java创建多线程使用Executors创造ExecutorService
- Java:使用Executors创建和管理线程
- java创建多线程使用Executors创造ExecutorService
- Java学习--线程池Executors的使用
- Java:使用Executors创建和管理线程
- Java的Executors(线程池)使用
- Java:使用Executors创建和管理线程
- java创建多线程使用Executors创造ExecutorService
- Java 使用Executors创建线程池
- Java:使用Executors创建和管理线程
- JAVA线程池类Executors的使用
- 开发windows服务
- :网友年龄 某君新认识一网友。 当问及年龄时,他的网友说: “我的年龄是个2位数,我比儿子大27岁, 如果把我的年龄的两位数字交换位置,刚好就是我儿子的年龄” 请你计算:网友的年龄一共有多少
- Unity 关于GetComponentsInChildren 利用扩展方法如何避免获取父物体
- 解决Charles乱码问题
- js时间转换(毫秒转换)
- JAVA中的Executors使用
- MATLAB与numpy矩阵中元素位运算的实现区别
- 文章标题
- JAVA基础算法——将字符串按照字典倒序排序并输出
- Java-青蛙跳台阶
- 浮躁
- CLR
- BZOJ 3288: Mato矩阵 行列式,线性筛
- Maven 手动添加 JAR 包到本地仓库