android应用开发实践教程-第9章java并发编程_第1页
android应用开发实践教程-第9章java并发编程_第2页
android应用开发实践教程-第9章java并发编程_第3页
android应用开发实践教程-第9章java并发编程_第4页
android应用开发实践教程-第9章java并发编程_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

目第一部分基础 第9章Java并发编 Java线简 Executor与 “3G( 9.7本章小 习题 第9Java本章导读:Android的应用程序支持多线程,多线程编程为我们充分利用系统资源提供UI和耗时操作提供了途径,提升了安卓用户的使用体验。线程((2Executor;Javajdk1.4jdk版本中,关于线的使用需要自己动手实现。jdk1.5出现后,并发线程这块发生了根本的变化,最重APIjdk1.5Executor来启动线程比用Threadstart()更好。我们可以很容易控制线程的启动、执行和关闭过程,还可以很容易使用线的特性,这归结于jdk1.5之后加入了java.util.concurrent包。这个包中主要介绍java线程以及线的使用,为我们在开发中处理线程问题提供了非常大的java.util.concurrent包含了并发编程中很常用的实用工具类。Executor是一个简单的标准化接口,用于定义类似于线程的自定义子系统,包括线、异步IO和轻量级任务框架。根据所使用的具体Executor类的不同,可能在新创建的线程中,现有的任务执行()提供了多个完整的异步任务执行框架。ExecutorService管理任务的排队和安排,并允许受的支持。ExecutorService提供了安排异步执行的方法,可执行由Callable表示的任何函数,结果类似于Runnable。Future返回函数的结果,允许确定执行是否完成,并提供取消执行的方法。RunnableFuture是拥有run方法的Future,run方法执行时将设置其结果。类ThreadPoolExecutor和ScheduledThreadPoolExecutor提供可调的、灵活的线。ExecutorsExecutor的常见类型和配置的工厂方法,以及使用它们的几种实用 publicinterfacepublicinterface}ExecutorRunnableExecutor而不是显式地创建线程。例如,可能会使用以下方法,而不是为一组任务中的每个任务调用newExecutorexecutor=anExecutor;Executorexecutor=anExecutor;{publicvoidexecute(Runnabler){}}{publicvoidexecute(Runnabler){newThread(r).start();}}ExecutorService继承了Executor,我们看一下ExecuteService{voidshutdown();booleanisShutdown();booleanbooleanawaitTermination(longtimeout,TimeUnitunit)throwsInterruptedException;<T>Future<T>submit(Runnabletask,Tresult);Future<?>submit(Runnabletask);throwsthrows<T>TinvokeAny(Collection<?extendsCallable<T>>throwsthrows<T>TinvokeAny(Collection<?extendsCallable<T>>tasks)throwsInterruptedException,ExecutionException;}shutdown()方法在终止前允许执行以前提交的任务,而shutdownNow()方法等待任ExecutorService以允许回收其资通过创建并返回一个可用于取消执行和/Futuresubmit扩展了基本方法Executor.execute(java.lang.Runnable)。线大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。 CachedThreadPool模式首先会按照需要创建足够多的线程来执行任务(Task)。随着程序任务。(code9CachedThreadPoolDemo工程)首先,任务定义如下(实现了Runnable接口,并且复写了run方法publicclassLiftOffimplementsRunnable protectedprotectedintcountDown=10;//DefaultprivatestaticinttaskCount=0;privatefinalintid=taskCount++;publicLiftOff(){}publicLiftOff(int{this.countDown=}publicStringstatus()return"#"+id+"("+(countDown>0?countDown:"LiftOff!")+")}publicvoidrun()while(countDown-->}}}publicclassCachedThreadPoolpublicclassCachedThreadPoolExecutorServiceexec=Executors.newCachedThreadPool();for(inti=0;i<10;i++){}}}10CachedThreadPool模式,execLiftOff(TaskFixedThreadPool模式创建一个定长线,可控制线程最大并发数,超出的线程会在任务(如果有的话CachedThreadPool是不同的,CachedThreadPool模FixedThreadPool模式下最多的线程数ExecutorServicefixedThreadPool=Executors.newFixedThreadPool(3);for(inti=0;i<18;i++){finalintindex=i;{publicvoidrun(){{);ExecutorServicefixedThreadPool=Executors.newFixedThreadPool(3);for(inti=0;i<18;i++){finalintindex=i;{publicvoidrun(){{);{}}}}}SingleThreadExecutor模式只会创建一个线程。它和FixedThreadPool比较类似,不过线SingleThreadExecutor的话,那么这些任务会被保存在SingleThreadExecutor模式可以保证只有一个任务会被执行。这种特点可以被用来处理publicstaticvoidpublicstaticvoidmain(String[]args)ExecutorServiceexec=for(inti=0;i<2;{exec.execute(new}}ScheduledThreadPool模式创建一个定长线,支持定时及周期性任务执行。publicstaticvoidmain(String[]args)publicvoidrun()System.out.println("delay1seconds,andexcuteevery3}},1,3,}}行每个提交的任务,通常使用Executors工厂方法配置。)和Executors.newSingleThreadExecutor()(单个线程,它们均为大多数使用场景 unit,BlockingQueue<Runnable> ThreadPoolExecutor(intcorePoolSize, intumPoolSize, longkeepAliveTime, BlockingQueue<Runnable>workQueue,RejectedExecutionHandlerhandler)说明:用给定的初始参数和默认的线程工厂创建新的ThreadPoolExecutor(intcorePoolSize, intumPoolSize, longkeepAliveTime, BlockingQueue<Runnable>workQueue,ThreadFactorythreadFactory)ThreadPoolExecutor(intcorePoolSize, intumPoolSize, longkeepAliveTime, BlockingQueue<Runnable>workQueue,ThreadFactorythreadFactory,RejectedExecutionHandlerhandler)的在JDK帮助文档中对ThreadPoolExecutor构造方法的参数是这样说明的:corePoolSize:池中所保存的线程数,包括空闲线程。umPoolSize:publicclassExecutorspublicclassExecutors{returnnewThreadPoolExecutor(nThreads,0L,new}{returnnewFinalizableDelegatedExecutorService(newThreadPoolExecutor(1,1,0L,new}60L,new}…}关于和最大池大小:ThreadPoolExecutor将根据corePoolSize设置的边界自动调整池大小。当新任务在方法execute(java.lang.Runnable)中提交时,如果运行的线程少于corePoolSize而少于umPoolSize,则仅当队列满时才创建新线程。如果设置的corePoolSize和umPoolSize相同,则创建了固定大小的线。如果将umPoolSize设置为基本的值(如Intege.MAX_ALUE,则允许池适应任意数setCorePoolSize(int)和setumPoolSize(int)进行动态更改。corePoolSize的线程,则这些多出的线BlockingQueue都可用于传输和保持提交的任务。可以使用此队程超出umPoolSize,在这种情况下,任务将被。SynchronousQueue,它将任务直接提交给线程而不保持它们。后才能继续添加。在这里不是线程便是新创建的线程。)直接提交通常要求LinkedBlockingQueuenewFixedThreadPool,根据前文提到的规则:如果运行的线程少于corePoolSizeExecutor始终首选添加新的线程,而不进行排队。那么当任务继续增加,会发生什么呢?如果运行的线程等于或多于corePoolSize,则Executor始终首 SynchronousQueue那样有其自身的特点,对于队列来说,总是可以加入的(资源耗尽,当然另当别论。换句说,也不会触发产生新的线程!corePoolSize大小的线程数会一直corePoolSize(因此,umPoolSize的值也就无效了。)当每个任务当使用有限的umPoolSizes时,有界队列(ArrayBlockingQueue)有助于防止CPU使用率、操作系统资源和上下文切换开销,但是可关于被的任务:当Executor已经关闭,并且Executor将有限边界用于最大线。在以上两种情况下,execute方法都将调用其RejectedExecutionHandler的java.util.concurrent.ThreadPoolExecutor)方法。}staticvoiduseThreadPool(intcount)finalList<Integer>list=newlongstartTime=ThreadPoolExecutortpe=newThreadPoolExecutor(1,1,finalRandomrandomnew //for(inti=0;i<count;{tpe.execute(newRunnable(){publicvoid{}}try, {}}staticvoiduseOneThread(intcount)finalList<Integer>list=newlongstartTime=finalRandomrandomnew //for(inti=0;i<count;{Threadthread=new{publicvoid{}try{}}我们看到在count参数为20000时,使用线 还有一个是使用线提交任务的例子,工程(源码) 结构见图9-1。 图9-2Future模式举的时间间隔内打印executor信息。程序的是WorkerPool的main方法。在初始化ThreadPoolExecutor时,我们保持初242。因此如果已经有四个正在执行的任务而此时分配来任务的话,工作队列将仅仅保留新任务中的两个,其他的将会被RejectedExecutionHandlerImpl处理。 接口Data的主要作用是:返回数据的接口。提供了getResult()RealData。publicpublicclassTest{Clientclient=newDatadata=client.request("name"); try}catch(Exceptione)}System.out.println("数据="+ //真实数}}publicclasspublicclassClientpublicDatarequest(finalStringqueryStr)finalFutureDatafuture=newnewThread //publicvoidrun()RealDatarealData=newRealData(queryStr);}}}publicpublicinterfaceData String}{protectedRealDatarealData=null;protectedbooleanisReady=false;{if(isReady){}isReady=true; }{while(!isReady){try{}catch(Exceptione)}}return}}{protectedStringpublicRealData(Stringpara //StringBuffersb=newStringBuffer();for(inti=0;i<10;i++){try{}catch(Exceptione)}result=}}{return}}=说明:FutureDataRealData的包装,是对真实数据的一个,封装了获取真实数=其它任何事儿,当流程进行到需要Future背后的对象时,可能有两种情况:get()get(longtimeoutTimeUnitunit)通过同步阻塞方式等待对象就绪。实际运行期是阻塞还是立即返回就取决于get()的调用时机和对象就绪的先java.util.concurrent.Callablejava.util.concurrent.FutureFuture模式。的目标对象生成之后,将之设置到Future之中,而当客户端真正需要目标对象时,目标对publicinterface{Vcall()throwspublicinterface{Vcall()throws可以使用Callable完成某个费时的工作,工作结束后传回结果对象,例如求质数。这里是在EclipseJavaEE中建立futuredemo_2工程,是JavaProject。publicclasspublicclassFutureDemopublicstaticvoidmain(String[]args)Callable<int[]>primeCallable=newPrimeCallable(1000);FutureTask<int[]>primeTask=newFutureTask<int[]>(primeCallable);Threadt=newThread(primeTask);try{ //( //for(intprime:primes){}}{{}}}{privateint{this.max=}publicint[]call()throws{int[]prime=newint[max+1];List<Integer>list=newArrayList<Integer>();for(inti=2;i<=max;i++)prime[i]=forinti2;i*imax;i这里可以改进if(prime[i]==1){for(intj=2*i;j<=max;{if(j%i==prime[j]=}}}for(inti=2;i<max;{if(prime[i]==1){}}int[]p=newint[list.size()];for(inti=0;i<p.length;i++){p[i]=}return}}PrimeCallableFuture来获得Callable执行的结果,从而在未来的时间点获得结果。2357111317192329…9419479539679712357111317192329…941947953967971977983991任务说项目讲 图9-3MobileMarketCity_3G_B工程 图9-4MobileMarketCity_3G_B工程运行界面com.mialab.marketcity包:主要包含主界面类MainA.mialab.marketcity.baseBaseA.mialab.marketcity.beans包:此包中放置的是实体类。 com.mialab.marketcity.views包:视图(控件)类包。主要包含Screen.java、(MobileaketCit_3,只不过是从网络异步加载的。主要运行界面如图9-4所示。网络位置:,测 android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>击宽带进入宽带列表界面如上图,但每一个item左侧的是异步从网络加载的。{privateLayoutInflatermInflater;privateListViewlistView;…mImageWorker=getImageWorker();mImageWorker.setOnScreen(Constants.APP_TAG,true);marketcity_BroadBand_Adapter=newmImageWorker,listView);…}…}imgUrl="if载。}典型代码及技术privateImageCacheprivateintloadingResId=0,errorResId=0,bgResId=0;privatevolatilebooleanonScreen=true;publicstaticintScreenWeith=privateHashMap<String,ImageCacheParams>params;privateHandlermHandler;publicstaticfinalintIO_BUFFER_SIZE=8*1024;privateOnHandleCacheListenermIHandleCache;{return}private{mHandler=newmImageCache=ImageCache.createCache();searchThreadPool=Executors.newFixedThreadPool(8);mIHandleCache=newOnHandleCacheListener(){publicvoidonSetImage(finalImageViewimageView,finalBitmapbitmap){{@Overridepublicvoidrun(){…}}{mHandler.post(newRunnable(){publicvoidrun()if(imageView!=null)…}}}}{SearchTasktask=getSearchTask(view);if(task!=null){finalStringtaskPath={}elsereturn}}return}privatevoidif||{searchThreadPool=searchThreadPool=}}}{}…}…}…}{Stringvolatilebooleanstop=intreqW=0;intintreqH= //stop=}publicSearchTask(finalStringpath,finalImageViewimageView,intw,inth,finalOnHandleCacheListenermIHandleCache){reqW=w;reqH=h;this.mIHandleCache=mIHandleCache;}publicvoidrun()…}…}须注意到:如果生成SearchTask对象,会含有弱 ImageView对象。以及boolean变量stop被为volatile。privateintdefaultId=0;privateinterrorResId=0;privateintbgresId=0;publicAsyncDrawable(intloadingRes,interrResId,intbgResid,SearchTasksearchTask){defaultId=loadingRes;bgresId=bgResid;}…} publicenum{// //////是否使用SD//是否在使用缓存前清理SDprivatestaticfinalbooleanDEFAULT_CLEAR_DISK_CACHE_ON_START=false;privateImageCacheParamsmImageCacheParams;privateDiskCache sd //{return}privateImageCache()}{}{mImageCacheParams=//Setupdisk…}//SetupmemorymMemoryCache=newLruCache<String,Bitmap>(cacheParams.memCacheSize){{return}}}} // if(data==null||bitmap==null)}if(mMemoryCache!=null&&mMemoryCache.get(data)=={mMemoryCache.put(data,bitmap);//Addtomemory}} if(mMemoryCache!=null)finalBitmapmemBitmap=mMemoryCache.get(path);if(memBitmap!=null){return}}return} //if(mMemoryCache!={}}//Aholderclassthatcontainscacheparameters.publicstaticclassImageCacheParams{publicbooleandiskCacheEnabled=DEFAULT_DISK_CACHE_ENABLED;publicintmemCacheSize=DEFAULT_MEM_CACHE_SIZE;publicbooleanclearDiskCacheOnStart=}…} 向的对象不会被回收,即使内存不足的时候。当强被置为NULL时,该对象象仍然占着内存。总之,我们不能保证可回收的对象被GC回收。GC算法以及GC运行时可用的内存数量。通俗地讲,内存空间足够,GC就不会回收它;如果内存空间不足了,就会回收这些对象的内存。 publicclassTest //创建是在常量池//创建一个弱 str指向String对象WeakReference<String>wr=newWeakReference<String>(str);str=null; //输出JAVA讲义 //强制 //输出null}}但是也有可能需要GC多次才能发现和释放弱的对象。MyObjectobj=newMyObject();ReferenceQueuerq=newReferenceQueue();WeakReferencewr=newWeakReference(obj,rq);objMyObjectobj=newMyObject();ReferenceQueuerq=newReferenceQueue();WeakReferencewr=newWeakReference(obj,rq);obj rq.poll();如果被GC回收了,wr.get()返回NULL,rq.poll()返回对象的弱wr。在应用程序UI界面加载一张是一件很简单的事情,但是当需要在界面上加载一大堆时,情况就变得复杂起来。在很多情况下,(比如使用ListView,GridView或者Vieger这样的组件,屏幕上显示的可以通过滑动屏幕等事件不断地增加,最终导致OOM(outofmemory,内存泄漏。片,它的主要算法原理是把最近使用的对象用强在LinkedHashMap中,并且把最,。LruCacheLruCache//intcacheSize=maxMemory/{//重写此方法来衡量每 }}{if(getBitmapFromMemCache(key)==null){mMemoryCache.put(key,bitmap);}}{return}大概会占用1.5兆的空间(800*480*4= {finalStringimageKey=finalBitmapbitmap{finalStringimageKey=finalBitmapbitmap=getBitmapFromMemCache(imageKey);if(bitmap!=null){}else}} { nBackground(Integer...params){// 加,params[0],100,100);returnbitmap;}volatile修饰符告诉JVM,该变量的线程必须总是使自己对该变量的私有副本与内在Javamainmemorymemory(例如寄存器。mainmemory中的值不一致的情况。memoryvolatilememoryvolatile{privatevolatilebooleanstop;publicvoidrun(){while(!stop)//dosome}} {stop=}}假如stop没有被 为volatile,线程执行run的时候检查的是自己的副本,就不能及时得知其他线程已经调用lMeToStop()修改了pleaseStop的值。}}ImageWorkerloadBitmap(finalStringpath,finalImageViewimageView,int…publicvoidloadBitmap(finalStringpath,final…publicvoidloadBitmap(finalStringpath,finalImageViewimageView,intloadingRes){loadBitmap(path,imageView,ScreenWeith/3,ScreenWeith/3,loadingRes,errorResId,bgResId);}publicvoidloadBitmap(finalStringpath,finalImageViewimageView,intw,inth,intloadingRes,interrRes,intbgRes){Bitmapresult=mImageCache.getBitmapFromMem(path);imageView.setBackgroundResource(bgRes>0?bgRes:0);if(result!=null&&!result.isRecycled()){finalSearchTasktask=newSearchTask(path,imageView,w,h,finalAsyncDrawableasyncDrawable=newAsyncDrawable(loadingRes,errRes,bgRes,task);if(!searchThreadPool.isTerminated()}}}}的cancelWork(imageView,path)方法,并判断其返回值。

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论