现在的位置: 首页 > 综合 > 正文

再读《Java编程思想》(Review 《Thinking in Java 3rd》)(13-16章)

2013年12月26日 ⁄ 综合 ⁄ 共 6275字 ⁄ 字号 评论关闭

原创文章,转载请注明出处:http://blog.csdn.net/wind5shy/article/details/5346490

第十三章并发

(By wind5shyhttp://blog.csdn.net/wind5shy)

Thread

n      start():初始化线程,使线程开始执行,Java虚拟机调用该线程的run()

n      yield():线程暂停,回到可执行状态,锁保留,让出CPU时间,但只让给同优先级的线程,所以如果某线程使用yield()后如果没有相同优先级的线程则该线程又会再次被执行。

n      sleep():线程暂停,回到可执行状态,锁保留,让出CPU时间,可使不同优先级的线程获得执行的机会。

n      join():等待该线程执行完毕。

n      setPriority():设置线程优先级。JDK10个优先级,但操作系统的优先级各不相同,所以无法做到完美的映射,可行的策略是只使用MIN_PRIORITYNORM_PRIORITYMAX_PRIORITY三个优先级。

n      setDaemon():将该线程标记为守护线程或用户线程(后台线程),当正在运行的线程都是守护线程时,Java虚拟机退出(即程序立即结束,如书上的例子)。后台线程创建的任何线程都会自动被设置为后台线程。

n      interrupt():中断线程。

n      interrupted():测试当前线程是否已经中断并清除线程的中断标识。换句话说,如果连续两次调用该方法,则第二次调用必定返回
false
异常捕获时也将清除线程的中断标识,所以异常被捕获时这个标识总是为false

n      isInterrupted():测试线程是否已经中断,线程的中断状态不受该方法的影响。

n      run()继承Thread或实现Runnable的一般目的就是改写run(),将要并发执行的代码需要写在里面。如果在子类中新建其他方法,如run1(),写在里面的代码是不能并发执行的。

 

synchronized关键字

synchronized修饰的代码为同步代码,只有获得对象锁(又称监视器)的线程才能访问这些代码,直到访问完成释放锁其他线程才能访问,但类中非synchronized的代码其他线程什么时候都可以访问。synchronized
static
锁的是class对象,所以相当于给整个类上锁。synchronized关键字不是方法签名(privatestatic
是)的一部分,所以在继承和重载的时候还是要同步的话需要手动加上。

一个例子:

synchronized f();

synchronized g();

h();

如果某线程正在执行f(),则其他线程不能执行同一对象的g(),但可以执行h()

 

原子操作

对除longdouble以外的基本类型进行简单的赋值或返回值操作是原子操作,longdouble加上valitale关键字后相应操作也是原子操作。但如果把这些操作写在方法里方法就不是该方法就不一定是原子操作了,比如int
i = 1
;这单个语句是原子操作没有问题(否则多线程下面的同步就没法控制了)但void setI { int i = 1}
就很可能不是原子操作了。

 

临界区/同步块:synchronized(object){//some
code}
,线程在进入some code(临界区)之前必须获得object
的锁(而不是包含这段代码的对象的锁)

 

Object的线程控制

n      wait():暂停当前线程(T)并释放当前对象的锁。T将其自身放置在对象的等待集中,然后放弃此对象上的所有同步要求。在发生以下四种情况之一前,T被禁用,且处于休眠状态:

1.      其他某个线程调用此对象的notify(),并且线T被任选为被唤醒的线程。

2.      其他某个线程调用此对象的notifyAll()

3.      其他某个线程中断T

4.      大约已经到达指定的实际时间。但是,如果timeout为零,则不考虑实际时间,在获得通知前T将一直等待。

然后,从对象的等待集中删除T,重新进行线程调度。然后,T以常规方式与其他线程竞争,以获得在该对象上同步的权利;一旦获得对该对象的控制权,该对象上的所有其同步声明都将被恢复到以前的状态,这就是调用wait()时的情况。然后,T
wait()
的调用中返回。所以,wait()返回时,该对象和T的同步状态与调用wait()
时的情况完全相同

wait(timeout)中的timeout只说明T在等待timeout时间后会被重新调度,从调度到wait(timeout)返回中还有一段T和其他线程竞争对象锁的时间,所以实际上wait(timeout)返回的时间会比timeout长。当然,正常情况下一般线程处理很快,竞争对象锁的时间一般较短,而timeout一般较长,两者在数量级上相差较大,所以wait(timeout)返回的时间和timeout差不了多少。

     

n      notify()/notifyAll():唤醒当前对象监视器(对象锁)上等待的单个/所有线程。(如果所有线程都在当前对象上等待,则会选择唤醒其中一个线程。)选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个
wait()
,在对象的监视器上等待。
直到当前线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在当前对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定当前对象的下一个线程方面没有可靠的特权或劣势。(这是
Sun JDK1.6 API中的解释,所以书中说线程在notify()之后就进入就绪状态是不完全正确。当然,实际情况中很可能只有notify()后的线程在等待对象锁,就可以马上获得锁而进入就绪状态。可以参考下面的线程状态图.

 

上面三个方法都只能作为拥有当前对象的锁的线程来调用,即只能在同步方法或同步块里使用。

 

线程状态

仅代表JVM中的线程状态,不代表操作系统中的线程状态。

n      NEW

至今尚未启动的线程处于这种状态。

n      RUNNABLE

正在 Java虚拟机中执行的线程处于这种状态。(调用Thread.sleep()后的线程仍处于这种状态,线程暂时放弃CPU但没有放弃对象锁。个人认为其实应该将RUNNABLE分为两种状态,一种RUNNABLE,表示线程获得了对象锁可以执行;一种为RUNNING,表示线程获得了CPU,正在执行)

n      BLOCKED

受阻塞并等待某个监视器锁(对象锁)的线程处于这种状态。当对象锁可用时所有阻塞的线程将进行争夺以获得对象锁进入可执行状态,失败的线程继续阻塞。

n      WAITING

无限期地等待另一个线程来执行某一特定操作的线程处于这种状态,即线程正在休眠等待其他线程的唤醒,唤醒后进入阻塞队列准备争夺对象锁。

n      TIMED_WAITING

等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。

n      TERMINATED

已退出的线程处于这种状态。

 

线程状态图

线程

 

死锁

必须同时满足的四个条件:

1.      互斥:有资源不能被共享。

2.      占有与请求:进程占有资源同时等待其他进程占有的资源。

3.      不剥夺:进程占有的资源不能被强行剥夺。

4.      循环等待:若干进程之间形成一种头尾相接的循环等待资源关系。

所以解除死锁只需打破其中一个条件即可。

(By wind5shyhttp://blog.csdn.net/wind5shy)

 

第十四章创建WindowsApplet程序

(By wind5shyhttp://blog.csdn.net/wind5shy)

Applet

Web浏览器中运行的小程序,用来增强浏览器中网页的功能。缺点一是不能访问本地盘(对一些经过签名的applet可以放宽限制),相应的安全性就比较好;二是每次都要重新下载所有内容,就会比较慢,但相应的就无需考虑安装和更新的问题。

 

框架

n      init():自动调用,对applet进行首次初始化,包括组件布局,用时须重载。

n      start():当applet进入Web浏览器视野时被调用,使applet开启其常规功能。也会在init()后被调用。

n      stop():当applet离开Web浏览器视野时被调用,使applet关闭其操作。也会在destroy()前被调用。

n      destroy():从网页中卸载applet时被调用。

 

Swing

驱动事件

Swing中(JavaBean中同样适用),图形组件接口和实现(组件相关事件发生时要执行的代码)分离,每个Swing组件可以报告其上所有可能发生的事件且能单独报告发生的每种事件,由“事件监听器”(一个实现了某种类型的监听器接口的类的对象)接受报告的事件并进行相应处理。所以只需要对感兴趣的事件创建监听器对象并进行注册(注册动作是通过调用报告事件的组件的addXXXListener()完成)即可,这样事件发生时就会执行相应的处理。例如:对JButton上感兴趣的事件为按键被按下,调用JButton.addActionListener(ActionListener
al)
al注册到JButton的按下按钮的事件上,al实现了ActionListener接口,接口里包含actionPerformed(),这样按下JButtonactionPerformed()就会被调用。

 

组件与相应事件与监听器

一般来说,组件名字为XXX的话,其事件为XXXEvent,监听器接口为XXXListener,添加和删除监听器的方法为addXXXListener()removeXXXListener()

 

监听器适配器

多于一个方法的接口,类从适配器继承,重写需要的方法,其他方法适配器以实现从而不需重写不需要的方法。

 

JNLP

Java网络发布协议,解决applet只能在浏览器上运行的问题,相当于加强版的applet,用于富客户端开发。一个JNLP客户端是一个应用程序,可以在运行时刻动态从网络上下载资源并自动检测程序的版本。

 

JavaBean

JavaBean就是可重用的组件,具有“能够被应用程序构建工具侦测其属性和事件的能力”。

 

命名规则

n      名为xxx的属性,需要有getXxx()setXxx()boolean型成员还可以用isXxx()代替getXxx())。应用程序构建工具通过这两个方法侦测Bean相应的属性。值得注意的是,Bean的属性只是对外暴露的某种数据,不一定和Bean对应的类中的成员有直接的对应关系。

n      普通方法必须是public。同样的,这指的是Bean对外暴露的方法,相应的类还是可以有非public的方法,不过这些方法就不是Bean的方法了。

n      若有构造器,则构造器需为public且无参数。

n      名为XxxEvent的事件对象,需要有addXxxListenerXxxListener)和remove
XxxListener
XxxListener),XxxListener为对Xxx
事件做出响应的对象。

一个类可以通过以上的规则被封装为一个JavaBean,这个Bean对外暴露一些属性、方法和事件,相当于Bean就是一个有特定规则的接口,类实现了这个接口。至于具体的内部实现,并没有特定的要求。

 

使用注意

n      JavaBean中的所有方法是synchronized的,除非确有必要的情绪下才移除synchronized关键字。

n      当一个多路事件(为一个事件注册了多个监听器)触发了一组对该事件感兴趣的监听器时,必须假定在偏历列表进行通知的时候,监听器可能被添加或删除。

 

判断是否同步重载方法

n      方法是否修改对象中的“关键”变量。关键的意思是指是否被程序中的其他线程读写。

n      方法是否依赖于“关键”变量。如果某个同步方法会修改此方法使用的变量,那方法就应该同步。不过还需要考虑这些变量在方法不同步的情况下程序最坏的情况,如果可以接受,也可以不同步。

n      查看父类的相应方法是否同步。不过同步不会继承,所以这条只是一个线索。

n      方法执行应该尽可能快,尽量把处理的开销移到方法外面。所以如果需要同步方法,说明可能违反了这个规则。

 

(By wind5shyhttp://blog.csdn.net/wind5shy)

 

第十五章发现问题

(By wind5shyhttp://blog.csdn.net/wind5shy)

Junit

每个测试类都扩展至TestCase,测试类中的每个测试方法都遵循格式:public
void testXXX()
即必须为public的无参数void方法,且以test
开头。

类中所有测试方法的对象都在测试运行的一开始即被同时创建。

setUp():可选,对测试对象进行初始化   ,在测试方法前被调用。

teardown():可选,在每个测试方法后进行清除工作(恢复静态数据、关闭文件等)。

 

断言

两种格式:

n      assert
boolean
表达式

n      assert
boolean
表达式;imformation错误提示信息

都表示此断言后的boolean表达式为true,否则抛出AssertionErrorboolean表达式可以是返回值为boolean的方法。

JDK断言功能默认为关闭,需手动打开。

 

DEC

对象遵循特定规则以构建强壮的程序。

契约:明确的行为,如类中的方法。

先验条件:执行行为前的条件,如方法的参数,在方法中首先用断言判断后再使用。

后验条件:执行行为后的结果,如方法的返回值,在得到结果返回之前用断言判断。

不变量:行为执行前后不改变的量,但在行为内部可以改变,如同催化剂在化学反应前后不改变,但会参与反应一样。在方法开始和结束时用断言判断是否一致。

实际中方法开始的不变量判断可以放弃,使用单元测试后验条件判断也可放弃,在确信方法不会将对象置于非法状态时方法结束的不变量判断也可以放弃,但一般不要放弃先验条件

 

Ant

Javabuild工具,用来构建项目,即处理项目中各个文件编译、打包、测试、相关依赖、应存放的位置等问题,EclipseIDE都集成了Ant,在使用时自动调用。

 

剖析和优化

内存消费

n      某特定类型分配的对象个数。

n      对象分配发生的地方。

n      该类实例分配中涉及到的方法。

n      闲散对象:已分配,但未使用也未回收的对象。引起内存泄露。

n      过度分配的临时对象,增加了垃圾回收器的工作量。

 

CPU使用

n      方法被调用的次数。

n      每个方法占有CPU的时间比。

n      每个方法花费的绝对时间,包括等待I/O时间,加锁时间等。

(By wind5shyhttp://blog.csdn.net/wind5shy)

 

第十六章分析与设计

(By wind5shyhttp://blog.csdn.net/wind5shy)

      这章没什么好说的。

(By wind5shyhttp://blog.csdn.net/wind5shy)

 

抱歉!评论已关闭.