java线程基本知识小结.doc_第1页
java线程基本知识小结.doc_第2页
java线程基本知识小结.doc_第3页
java线程基本知识小结.doc_第4页
java线程基本知识小结.doc_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

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

文档简介

java线程基本知识小结 看了一阵子java线程方面的知识,thinking in java 3rd,effective java 2nd,感觉还是雾里看花,难以得其精髓。多线程编程本来就是一门很玄奥的学问,不是看一些基础的语法知识就能真正掌握的。在实践中去揣摩,我想才是最好的方法。奈何我现在没有这样的条件,离论文开题的时间不远了,我还没有摸到头绪,真不知道是该坚持还是放弃。扯远了,还是回到线程来吧,虽然不得要领,但还是要把一些基础的东西总结一下,一旦以后需要用到的时候,也可以方便地回顾。1. 线程的创建java中创建一个线程有两种方式:1.1. 扩展Thread类,并重载run()方法publicclassThreadNameextendsThreadpublicvoidrun()/dosomethinghere1.2. 实现runnable接口,并调用Thread提供的构造函数publicclassThreadNameimplementsRunnablepublicvoidrun()/TODOAuto-generatedmethodstubpublicvoidmain(Stringargs)Threadthread=newThread(newThreadName();thread.start();这两种方法各有利弊。简单来说,如果你确定当前的类就是作为一个单纯的线程来实现,不需要再继承其他任何类的时候,那么最好就用第一种方式,因为简单,而且可以直接就获得Thread所提供的各种方法,在类内部使用;反之,如果你需要继承其他类,或者将来可能会有这种需要,那么就用第二种方法。第二种方法需要注意的地方是,当你实现了Runnable接口后,你仅仅是实现了该接口而已,你现在所有的只是一个run()方法,即使你生成一个对象来调用run()方法,和普通的方法调用也没什么两样,并不会创建一个新的线程。只有当你用Thread构造函数创建一个对象之后,这才是新创建了一个线程。当你使用第二种方法的时候,可能你也想在类内部调用Thread所提供的一些方法,这时可以用Thread.currentThread()来获得当前线程的引用。2. 线程的运行当你获得一个线程实例thread后,使他开始运行的唯一方法就是thread.start(),由java虚拟机调用该线程的run方法。注意不是调用run()方法来启动线程。当你调用run()方法时,如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。另外要注意,多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。3. 结束线程运行就我目前所知,有两种结束线程的方法(我是指通过直接操作线程对象的合法方法)。3.1. 在线程内部设置一个标记为volatile的标志位publicclassStopThreadextendsThreadpublicvolatilebooleanstop=false;privatestaticinti=0;publicvoidrun()while(!stop)i+;System.out.println(i);/*/*paramargs*/publicstaticvoidmain(Stringargs)StopThreadthread=newStopThread();thread.start();trysleep(2000);catch(InterruptedExceptione)/TODOAuto-generatedcatchblocke.printStackTrace();thread.stop=true;关于volatile的说明可能需要先了解JAVA的内存模型,简单点说就是JVM有个主存,各个线程再有各自的工作内存,两个存放的地方带来的问题就是不一致。volatile就是为了解决这个不一致出现的。使用volatile会每次修改后及时的将工作内存的内容同步回主存。这样,线程所看到的就是最新的值,而不是被缓存的值。注,这里还牵涉到“原子操作”的概念。所谓原子操作,大体上就是指操作只由一个指令即可完成,不需要上下文切换。在java中,对除long和double之外的基本类型进行简单的赋值或者返回值操作的时候,才是原子操作。然而,只要给long或double加上volatile,就和其他基本类型一样了。但自增操作并不是原子操作,它牵涉到一次读一次写!正因为对boolean的操作是原子操作,我们不用担心多个线程同时对boolean值进行修改而导致不一致的情况,所以在修改、读取boolean值的时候不需要加synchronized关键字。3.2. 调用interrrupt()方法有的时候,线程可能会阻塞,比如在等待输入的时候,并且他也不能轮询结束标志。这个时候,可以用Terrupt()方法来跳出阻塞代码。publicclassBlockedextendsThreadpublicBlocked()System.out.println(Starting);publicvoidrun()trysynchronized(this)wait();catch(InterruptedExceptione)System.out.println(Interrupted);System.out.println(Exitingrun();publicstaticvoidmain(Stringargs)Blockedthread=newBlocked();thread.start();trysleep(2000);catch(InterruptedExceptione)/TODOAuto-generatedcatchblocke.printStackTrace();errupt();thread = null;注意,我们在用interrupt终止线程后,最好再将该线程赋为null,这样垃圾回收器就可以回收该线程了。另,使用interrupt()并不需要获得对象锁 这与wait()、notify()等不同上面例子中有一个比较tricky的地方:当我们使用interrupt()方法中断线程的运行时,线程将抛出InterruptedException,但在抛出exception的同时,他的中断状态将被清除,所以如果我们在catch(InterrruptedException e) 里调用isInterrupted(),返回的结果将会是false。当你使用Timer类调度线程的时候,可以使用Timer类提供的cancel()方法来终止线程的运行。Timer类还是比较好用的,具体参见API doc。4. wait(), notify(), notifyAll()这三个方法是线程同步机制的基础,但这三种方法已经被Joshua Bloch视为“low-level”的,“汇编级别”的代码,应该尽量被JDK 1.5以来提供的高层次框架类取代。这正是java让人又爱又恨的地方 它总是提供各种方便易用的API供使用者调用,帮助编程人员提高效率,避免错误,但与此同时,它也在无形之间将底层机制与使用隔离,使相当一批编程者“沦为”API的“纯”调用者,只懂得用一堆API来堆起一个程序。很不幸,我就是其中之一。但我总算还保留着一点求知的欲望。使用wait(),总是要最先想到,一定要用while循环来判断执行条件是否满足:synchronized(obj)while(conditionIsNotMet)wait();/Performactionapproriatetocondition这样就可以保证在跳出等待循环之前条件将被满足,如果你被不相干的条件所通知(比如notifyAll()),或者在你完全退出循环之前条件已经改变,你被确保可以回来继续等待。对于notify(), notifyAll(),Joshua Bloch的建议是尽量使用notifyAll(),以避免出现某些进程永远沉睡的现象。5. synchronizedsynchronized是将对象中所有加锁的方法(or代码块)锁定。由于同一时间只能有一个线程拥有对象的锁,这也就保证了互斥。有两种加锁形式:5.1. 给代码块加锁:synchronized(obj)/somecodeshere5.2. 给方法加锁:publicsynchronizedvoidmethod()/somecodeshere注意,java中不允许在重载(重写?)的时候改变签名,但sychronized关键字并不属于签名,因此,你可以继承一个类,然后重载(重写?)这个几类的方法,加上sychronized关键字来保证互斥以上介绍了java线程中语法上的一些基础的东西,下面要介绍的同样也是基础,但同上面而言还是有些差异,还是分开一段来介绍的好。1. 一些方法sleep():sleep()方法能迫使线程休眠指定长的时间。在调用sleep()方法的时候,必须把它放在try块中,因为在休眠时间到期之前有可能被打断。如果某人持有对此线程的引用,并且在此线程上调用了interrupt()方法,就会发生这种情况。daemon线程:必须在线程启动之前调用setDaemon()方法,才能把它设置为后台线程。一个后台线程所创建的任何线程都将被自动设置成后台线程join():一个线程可以在其他线程之上调用join()方法,其效果是等待一段时间直到第二个线程结束才继续执行。如果某个线程在另一个线程t上调用t.join(),此线程将被挂起,直到目标线程t结束才恢复(即t.isAlive()返回为false)你也可以在调用join()时带上一个超时参数(单位可以是毫秒或者毫秒纳秒),这样如果目标线程在这段时间到期还没结束的话,join()方法总能返回。对join()方法的调用可以被中断,做法是在调用线程上使用interrupt()方法,这时需要用到try-catch2. 线程的四种状态:创建、就绪、死亡、阻塞。应该还有一个运行状态吧线程进入阻塞状态可能有如下四种原因:2.1. 通过调用sleep()使线程进入休眠状态。在这种情况下,线程在指定时间内不会运行2.2. 通过调用wait()使线程挂起,直到线程得到了notify()或notifyAll()消息,线程才会进入就绪状态2.3. 线程在等待输入/输出操作的完成2.4. 线程试图在某个对象上调用其同步控制方法,但是对象锁不可用3. 只有当下列四个条件同时满足时,才会发生死锁:3.1. 互斥条件:线程使用的资源中至少又一个是不能共享的3.2. 至少有一个进程持有一个资源,并且他在等待获取一个当前被别的进程持有的资源。3.3. 资源不能被进程抢占。所有的进程必须把资源释放作为普通事件。3.4. 必须有循环等待,即,一个线程等待其他线程持有的资源,后者又在等待另一个进程持有的资源,这样一直下去,直到又一个进程在等待第一个进程持有的资源,使得大家都被锁住。要发生死锁,必须这四个条件同时满足,所以,只要破坏其中任意一个,就可以打破死锁。其中第四个条件是最容易被打破的。4. java中对以“管道”形式对线程的输入/输出提供了支持。PipedWriter类允许线程向管道写;PepedReader类允许不同线程从一个管道中读取。下面是对effective java 2nd中Concurrency一章的总结。感觉这一章并不如我所想象的那样,对java的线程机制有一个全面透彻的解说,反而是花了很大力气宣传一本书 Java Concurrency in Practice。好吧,想在一章的内容里对java线程的认识达到某种高度,怎么想也是不太现实的。但这本书究竟如何,我还没看过,不作评论,但我想肯定是很适合正在用java线程做项目的人的。对我而言,重要的不是学会怎么用java代码来写出多线程程序,而是搞清线程内部的机制。下面对Concurrency一章的重点知识(我认为重要的)进行一下总结:Item 66: Synchronize access to shared mutable data when multiple threads share mutable data, each thread that reads or writes the data must perform synchronization. (读写都要加锁,不能只加一个) If you need only inter-thread communication, and not mutual exclusion, the volatile modifier is an acceptable form of synchronization, but it can be tricky to use correctly. Item 67: Avoid excessive synchronization Inside a synchronized region, do not invoke a method that is designed to be overridden, or one provided by a client in the form of a function object As a rule, you should do as little work as possible inside synchronized regions. In summary, to avoid deadlock and data corruption, never call an alien method from within a synchronized region. More generally, try to limit the amount of work that you do from within synchronized regions. Item 68: Prefer executors and tasks to threads Executor Framework - refer to Java Concurrency in Practice Item 69: Prefer concurrency utilities to wait and notify Given the difficulty of using wait and notify correctly, you should use the higher-level concurrency utilities instead. The higher-level utilities in java.util.concurrent fall into three categories: the Executor Framework; concurrent collections; and synchronizers. Synchronizers are objects that enable threads to wait for one another, allowing them to coordinate their activities. The most commonly used synchronizers are CountDownLatch and Semaphore. Less commonly used are CyclicBarrier and Exchanger. For interval timing, always use System.nanoTime in preference to System.currentTimeMillis. Always use the wait loop idiom to invoke the wait method; never invoke it outside of a loop. The notifyAll method should generally be used in preference to notify. If notify is used, great care must be taken to ensure liveness. Item 70: Document thread safety Conditionallythread-safe classes must document which method invocation sequences require external synchronization, and which lock to acquire when executing these sequences. If you write an unconditionally thread-safe class, consider using a private lock object in place of synchronized methods. This protects you against synchronization interference by clients and subclasses and gives you the flexibility to adopt a more sophisticated approach to concurrency control in a later release. Item 71: Use lazy initialization judiciously In summary, you should initialize most fields normally, not lazily. If you must initialize a field lazily in order to achieve your performance goals, or to break a harmful initialization circularity, then use the appropriate lazy initialization technique. For instance fields, it is the double

温馨提示

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

评论

0/150

提交评论