最近在看一本书,名字叫“Java Network programming”, 里面关于线程的讲述很有见解,现把大概意思记录如下:
一、我的书架上有很多书,有的书的年龄已经超过15年了,还有的书我已经10年没有看了,可能我这一辈子也不会再看了,这些书一共花去我1万多美元。有趣的是,离我家不远处就有一个公共图书馆,我可以去那里看书。如果我去图书馆的话就存在一些问题:我不能把书带回家看,我也不能在书的空白处作标记,更烦人的是我可能借不到我想看的书,因为别人已经借走了。但如果我去公共图书馆,我也有利可图,就是我可以花很少的钱并且我不用专门在家找一个地方放书。
如果从线程和进程的角度来看此事则可以这样解释。进程就像一个公共图书馆,它有各种资源,而线程则是每个借书人。如果每个人要借的书不同,那么执行速度一定会得到提升;但如果每个人要借的书相同,则第二人必须等第一个人把书还后才能借到书。书是资源,但有时必须设置它进行排外的访问(即临界区),不然就会出现混乱情况,这也就是线程同步(synchronization)的原因。
我们应该看到,一个进程内的所有线程都是共享进程下的内存空间,当编程时,我们大脑里应该想着内存空间是如何被利用的,这样对一些问题就能迎刃而解。
二、有关线程安全
线程的同步(synchronized)是以“对象”(一个类的this关键字)作为锁(lock)的。当一个对象被多个线程使用时,此对象就会有线程安全问题。如果一个类没有数据成员(Field),则由它产生的对象是线程安全的, 这是因为每个方法(method)都是线程安全的,因为方法的局部变量都是一个新的对象。对于方法参数(method arguments),如果它是原始类型(primitive type)则是线程安全的(java是值传递),如果是对象类型(object type)则会存在线程安全问题。一般情况下,构造方法(constructor)是线程安全的,因为一个对象不会还没有创建完成就被多个线程引用,但如果构造方法内引用了其它线程的对象也可能造成线程安全问题,但这种情况是不常见的(uncommon)。一个不变的(Immutable)对象一定是线程安全的,“不变的”可以这样行成:声明它所有的字段(Field)都是私有的(private),并用不提供修改这些字段(Field)的方法(method), java类库中的“不变类”有java.lang.String, java.lang.Integer, java.lang.Double等。
在编写一个线程安全相关的类时,首先根据这个类会产生许多对象,只有当几个线程同时引用一个对象时才会有线程安全问题。因此类里面的有关线程同步(synchronized)的块(block)或方法(method)是针对象而言的。但单例模式(singleton pattern)可以作为特例考虑。
三、线程的调度(scheduling)
现在的虚拟机(VM)采用的大都是抢占式(preemption)线程调度,即高优先级(high-priority)的线程出抢占低优先级(low-priority)线程的CPU时间。线程可以调用静态方法 public static void yield() 来让出自己的CPU时间,但并不一定有作用,而且这个让出CPU时间的线程并不会释放自己的资源和拥有的锁(lock).
四、说一下Thread类中的interrupt( ) 方法
interrupt()方法的调用,它主要用在线程阻塞太长时间了,不再用它了,如何把它结束掉呢,可以在三种环境下发生线程超时情况: 1 线程被wait(), join(), sleep() 此类方法阻塞(block);2 线程被I/O阻塞(block);3 线程被Selector阻塞。 2,3种情况还没有接触到,这里先不谈,我们说一下第1种情况,2,3种情况和这类似。看下面一段代码:
执行结果如下:
New-thread will start...
New-thread start looping...
New-thread is running...
New-thread will be waked up from sleep.
New-thread is interrupted...
New-thread will quit...
Application is over...
我们在main 方法中调用 newThread.interrupt() ,这样正在 sleep 的newThread 就会抛出 InterruptedException 异常,同进newThread也就醒了,我们在处理异常时把 flag 设置为 true, 则while循环就会终止,达到我们结束newThread线程的目的,如果在处理异常时不设置flag为true,则newThread,又开始执行了!