java线程基本知识小结

上传人:宝路 文档编号:23264095 上传时间:2017-11-30 格式:DOC 页数:13 大小:162.01KB
返回 下载 相关 举报
java线程基本知识小结_第1页
第1页 / 共13页
java线程基本知识小结_第2页
第2页 / 共13页
java线程基本知识小结_第3页
第3页 / 共13页
java线程基本知识小结_第4页
第4页 / 共13页
java线程基本知识小结_第5页
第5页 / 共13页
点击查看更多>>
资源描述

《java线程基本知识小结》由会员分享,可在线阅读,更多相关《java线程基本知识小结(13页珍藏版)》请在金锄头文库上搜索。

1、java 线程基本知识小结 看了一阵子 java 线程方面的知识, thinking in java 3rd,effective java 2nd,感觉还是雾里看花,难以得其精髓。多线程编程本来就是一门很玄奥的学问,不是看一些基础的语法知识就能真正掌握的。在实践中去揣摩,我想才是最好的方法。奈何我现在没有这样的条件,离论文开题的时间不远了,我还没有摸到头绪,真不知道是该坚持还是放弃。扯远了,还是回到线程来吧,虽然不得要领,但还是要把一些基础的东西总结一下,一旦以后需要用到的时候,也可以方便地回顾。1. 线程的创建java 中创建一个线程有两种方式:1.1. 扩展 Thread 类,并重载 ru

2、n()方法public class ThreadName extends Thread public void run() / do something here1.2. 实现 runnable 接口,并调用 Thread 提供的构造函数public class ThreadName implements Runnable public void run() / TODO Auto-generated method stubpublic void main(String args) Thread thread = new Thread(new ThreadName();thread.start

3、();这两种方法各有利弊。简单来说,如果你确定当前的类就是作为一个单纯的线程来实现,不需要再继承其他任何类的时候,那么最好就用第一种方式,因为简单,而且可以直接就获得Thread 所提供的各种方法,在类内部使用;反之,如果你需要继承其他类,或者将来可能会有这种需要,那么就用第二种方法。第二种方法需要注意的地方是,当你实现了 Runnable 接口后,你仅仅是实现了该接口而已,你现在所有的只是一个 run()方法,即使你生成一个对象来调用 run()方法,和普通的方法调用也没什么两样,并不会创建一个新的线程。只有当你用 Thread 构造函数创建一个对象之后,这才是新创建了一个线程。当你使用第二

4、种方法的时候,可能你也想在类内部调用 Thread 所提供的一些方法,这时可以用 Thread.currentThread()来获得当前线程的引用。2. 线程的运行当你获得一个线程实例 thread 后,使他开始运行的唯一方法就是 thread.start(),由 java虚拟机调用该线程的 run 方法。注意不是调用 run()方法来启动线程。当你调用 run()方法时,如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。另外要注意,多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。

5、3. 结束线程运行就我目前所知,有两种结束线程的方法(我是指通过直接操作线程对象的合法方法)。3.1. 在线程内部设置一个标记为 volatile 的标志位public class StopThread extends Thread public volatile boolean stop = false;private static int i = 0;public void run() while(!stop) i+;System.out.println(i);/* param args */public static void main(String args) StopThread t

6、hread = new StopThread();thread.start();try sleep(2000); catch (InterruptedException e) / TODO Auto-generated catch blocke.printStackTrace();thread.stop = true;关于 volatile 的说明可能需要先了解 JAVA 的内存模型,简单点说就是 JVM 有个主存,各个线程再有各自的工作内存,两个存放的地方带来的问题就是不一致。volatile 就是为了解决这个不一致出现的。使用 volatile 会每次修改后及时的将工作内存的内容同步回主存

7、。这样,线程所看到的就是最新的值,而不是被缓存的值。注,这里还牵涉到“原子操作”的概念。所谓原子操作,大体上就是指操作只由一个指令即可完成,不需要上下文切换。在 java 中,对除 long 和 double 之外的基本类型进行简单的赋值或者返回值操作的时候,才是原子操作。然而,只要给 long 或 double 加上 volatile,就和其他基本类型一样了。但自增操作并不是原子操作,它牵涉到一次读一次写!正因为对 boolean 的操作是原子操作,我们不用担心多个线程同时对 boolean 值进行修改而导致不一致的情况,所以在修改、读取 boolean 值的时候不需要加 synchroni

8、zed 关键字。3.2. 调用 interrrupt()方法有的时候,线程可能会阻塞,比如在等待输入的时候,并且他也不能轮询结束标志。这个时候,可以用 Thread.interrupt()方法来跳出阻塞代码。public class Blocked extends Thread public Blocked() System.out.println(Starting);public void run() try synchronized(this) wait(); catch(InterruptedException e) System.out.println(Interrupted);Sys

9、tem.out.println(Exiting run();public static void main(String args) Blocked thread = new Blocked();thread.start(); try sleep(2000); catch (InterruptedException e) / TODO Auto-generated catch blocke.printStackTrace();thread.interrupt();thread = null;注意,我们在用 interrupt 终止线程后,最好再将该线程赋为 null,这样垃圾回收器就可以回收该

10、线程了。另,使用 interrupt()并不需要获得对象锁 这与 wait()、notify() 等不同上面例子中有一个比较 tricky 的地方:当我们使用 interrupt()方法中断线程的运行时,线程将抛出 InterruptedException,但在抛出 exception 的同时,他的中断状态将被清除,所以如果我们在 catch(InterrruptedException e) 里调用 isInterrupted(),返回的结果将会是 false。当你使用 Timer 类调度线程的时候,可以使用 Timer 类提供的 cancel()方法来终止线程的运行。Timer 类还是比较好

11、用的,具体参见 API doc。4. wait(), notify(), notifyAll()这三个方法是线程同步机制的基础,但这三种方法已经被 Joshua Bloch 视为“low-level”的,“汇编级别”的代码,应该尽量被 JDK 1.5 以来提供的高层次框架类取代。这正是 java 让人又爱又恨的地方 它总是提供各种方便易用的 API 供使用者调用,帮助编程人员提高效率,避免错误,但与此同时,它也在无形之间将底层机制与使用隔离,使相当一批编程者“沦为”API的“纯”调用者,只懂得用一堆 API 来堆起一个程序。很不幸,我就是其中之一。但我总算还保留着一点求知的欲望。使用 wait

12、(),总是要最先想到,一定要用 while 循环来判断执行条件是否满足:synchronized(obj) while(conditionIsNotMet) wait();/ Perform action approriate to condition这样就可以保证在跳出等待循环之前条件将被满足,如果你被不相干的条件所通知(比如notifyAll()),或者在你完全退出循环之前条件已经改变,你被确保可以回来继续等待。对于 notify(), notifyAll(),Joshua Bloch 的建议是尽量使用 notifyAll(),以避免出现某些进程永远沉睡的现象。5. synchronize

13、dsynchronized 是将对象中所有加锁的方法(or 代码块)锁定。由于同一时间只能有一个线程拥有对象的锁,这也就保证了互斥。有两种加锁形式:5.1. 给代码块加锁:synchronized(obj) / some codes here5.2. 给方法加锁:public synchronized void method() / some codes here注意,java 中不允许在重载(重写?)的时候改变签名,但 sychronized 关键字并不属于签名,因此,你可以继承一个类,然后重载(重写?)这个几类的方法,加上 sychronized 关键字来保证互斥以上介绍了 java 线程

14、中语法上的一些基础的东西,下面要介绍的同样也是基础,但同上面而言还是有些差异,还是分开一段来介绍的好。1. 一些方法sleep():sleep()方法能迫使线程休眠指定长的时间。在调用 sleep()方法的时候,必须把它放在 try 块中,因为在休眠时间到期之前有可能被打断。如果某人持有对此线程的引用,并且在此线程上调用了 interrupt()方法,就会发生这种情况。daemon 线程:必须在线程启动之前调用 setDaemon()方法,才能把它设置为后台线程。一个后台线程所创建的任何线程都将被自动设置成后台线程join():一个线程可以在其他线程之上调用 join()方法,其效果是等待一段

15、时间直到第二个线程结束才继续执行。如果某个线程在另一个线程 t 上调用 t.join(),此线程将被挂起,直到目标线程 t结束才恢复(即 t.isAlive()返回为 false)你也可以在调用 join()时带上一个超时参数(单位可以是毫秒或者毫秒纳秒),这样如果目标线程在这段时间到期还没结束的话,join()方法总能返回。对 join()方法的调用可以被中断,做法是在调用线程上使用 interrupt()方法,这时需要用到try-catch2. 线程的四种状态:创建、就绪、死亡、阻塞。应该还有一个运行状态吧线程进入阻塞状态可能有如下四种原因:2.1. 通过调用 sleep()使线程进入休眠

16、状态。在这种情况下,线程在指定时间内不会运行2.2. 通过调用 wait()使线程挂起,直到线程得到了 notify()或 notifyAll()消息,线程才会进入就绪状态2.3. 线程在等待输入/输出操作的完成2.4. 线程试图在某个对象上调用其同步控制方法,但是对象锁不可用3. 只有当下列四个条件同时满足时,才会发生死锁:3.1. 互斥条件:线程使用的资源中至少又一个是不能共享的3.2. 至少有一个进程持有一个资源,并且他在等待获取一个当前被别的进程持有的资源。3.3. 资源不能被进程抢占。所有的进程必须把资源释放作为普通事件。3.4. 必须有循环等待,即,一个线程等待其他线程持有的资源,后者又在等待另一个进程持有的资源,这样一直下去,直到又一个进程在等待第一个进程持有的资源,使得大家都被锁住。要发生死锁

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 其它办公文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号