??xml version="1.0" encoding="utf-8" standalone="yes"?>
有的文章dASSERTQ点q里Q,是淆了其用目的的l果?nbsp; 阅读全文
]]>
]]>
]]>
1、谁创徏U程Q?
即(zhn)从未显式地创徏一个新U程Q?zhn)仍可能会发现自己在用线E。线E被从各U来源中引入到我们的E序中?
有许多工具可以ؓ(zhn)创建线E,如果要用这些工P应该了解U程如何交互Q以及如何防止线E互相干扰?
2、AWT ?Swing
M使用 AWT ?Swing 的程序都必须处理U程。AWT 工具创建单个线E,用于处理 UI 事gQQ何由 AWT 事g调用的事件侦听器都在 AWT 事gU程中执行?
(zhn)不仅必d心同步对事g侦听器和其它U程之间׃n的数据项的访问,而且q必LCU方法,让由事g侦听器触发的长时间运行Q务(如在大文档中查拼写或在文件系l中搜烦一个文Ӟ 在后台线E中q行Q这样当该Q务运行时QUI ׃会停滞了Q这可能q会L用户取消操作Q。这样做的一个好的框架示例是 SwingWorker c?br> AWT 事gU程q不是守护程序线E;q就是通常使用 System.exit() l束 AWT ?Swing 应用E序的原因?
3、?TimerTask
JDK 1.3 中,TimerTask 工具被引入到 Java 语言。这个便利的工具让?zhn)可以E后在某个时间执行Q务(例如Q即从现在v十秒后运行一ơQ务)Q或者定期执行Q务(卻I每隔十秒q行dQ?
实现 Timer c非常简单:它创Z个计时器U程Qƈ且构Z个按执行旉排序的等待事仉列?
TimerTask U程被标记成守护E序U程Q这样它?yu)׃会阻止程序退出?
因ؓ计时器事件是在计时器U程中执行,所以必ȝ保正同步了针对计时器Q务中使用的Q何数据项的访问?
?CalculatePrimes CZ中,q没有让ȝE休眠,我们可以使用 TimerTaskQ方法如下:
public static void main(String[] args) {
Timer timer = new Timer();
final CalculatePrimes calculator = new CalculatePrimes();
calculator.start();
timer.schedule(
new TimerTask() {
public void run()
{
calculator.finished = true;
}
}, TEN_SECONDS);
}
4、servlet ?JavaServer Pages 技?
servlet 容器创徏多个U程Q在q些U程中执?servlet h。作?servlet ~写者,(zhn)不知道Q也不应该知道)(zhn)的h会在什么线E中执行Q如果同时有多个对相?URL 的请求入站,那么同一?servlet 可能会同时在多个U程中是zd的?
当编?servlet ?JavaServer Pages (JSP) 文gӞ必须始终假设可以在多个线E中q发地执行同一?servlet ?JSP 文g。必适当同步 servlet ?JSP 文g讉K的Q何共享数据;q包?servlet 对象本n的字Dc?
5、实?RMI 对象
RMI 工具可以让?zhn)调用对在其?JVM 中运行的对象q行的操作。当调用q程Ҏ(gu)ӞRMI ~译器创建的 RMI 存根会打包方法参敎ͼq过|络它们发送到q程pȝQ然后远E系l会它们解包ƈ调用q程Ҏ(gu)?
假设(zhn)创Z一?RMI 对象Qƈ它注册?RMI 注册表或?Java 命名和目录接口(Java Naming and Directory Interface (JNDI)Q名U空间。当q程客户用其中的一个方法时Q该Ҏ(gu)会在什么线E中执行呢?
实现 RMI 对象的常用方法是l承 UnicastRemoteObject。在构?UnicastRemoteObject Ӟ会初始化用于分派q程Ҏ(gu)调用的基l构。这包括用于接收q程调用h的套接字侦听器,和一个或多个执行q程h的线E?
所以,当接收到执行 RMI Ҏ(gu)的请求时Q这些方法将?RMI 理的线E中执行?
6、小l?
U程通过几种机制q入 Java E序。除了用 Thread 构造器中显式创建线E之外,q可以用许多其它机制创徏U程Q?br> AWT ?Swing
RMI
java.util.TimerTask 工具
servlet ?JSP 技?
׃n变量
1?׃n变量
要多个U程在一个程序中有用Q它们必L某种Ҏ(gu)可以互相通信或共享它们的l果?
让线E共享其l果的最单方法是使用׃n变量。它们还应该使用同步来确保g一个线E正传播到另一个线E,以及防止当一个线E正在更C些相x据项Ӟ另一个线E看C一致的中间l果?
U程基础中计素数的CZ使用了一个共享布?yu)变量,用于表示指定的时间段已经q去了。这说明了在U程间共享数据最单的形式是:轮询׃n变量以查看另一个线E是否已l完成执行某Q务?
2、存在于同一个内存空间中的所有线E?
正如前面讨论q的Q线E与q程有许多共同点Q不同的是线E与同一q程中的其它U程׃n相同的进E上下文Q包括内存。这非常便利Q但也有重大责Q。只要访问共享变量(静态或实例字段Q,U程可以方便地互相交换数据Q但U程q必ȝ保它们以受控的方式访问共享变量,以免它们互相q扰Ҏ(gu)的更攏V?
MU程可以讉K所有其作用域内的变量,pȝE可以访问该变量一栗素数示例用了一个公用实例字D,叫做 finishedQ用于表C已l过了指定的旉。当计时器过期时Q一个线E会写这个字D;另一个线E会定期dq个字段Q以查它是否应该停止。注Q这个字D被声明?volatileQ这对于q个E序的正运行非帔R要。在本章的后面,我们看到原因?
3、受控访问的同步
Z保可以在线E之间以受控方式׃n数据QJava 语言提供了两个关键字Qsynchronized ?volatile?
Synchronized 有两个重要含义:它确保了一ơ只有一个线E可以执行代码的受保护部分(互斥Qmutual exclusion 或者说 mutexQ,而且它确保了一个线E更改的数据对于其它U程是可见的Q更改的可见性)?
如果没有同步Q数据很Ҏ(gu)处于不一致状态。例如,如果一个线E正在更C个相兛_|比如Q粒子的位置和速率Q,而另一个线E正在读取这两个|有可能在W一个线E只写了一个|q没有写另一个值的时候,调度W二个线E运行,q样它就会看C个旧值和一个新倹{同步让我们可以定义必须原子地运行的代码块,q样对于其他U程而言Q它们要么都执行Q要么都不执行?
同步的原子执行或互斥斚wcM于其它操作环境中的界段的概c?
4、确保共享数据更改的可见?
同步可以让我们确保线E看C致的内存视图?
处理器可以用高速缓存加速对内存的访问(或者编译器可以值存储到寄存器中以便q行更快的访问)。在一些多处理器体pȝ构上Q如果在一个处理器的高速缓存中修改了内存位|,没有必要让其它处理器看到q一修改Q直到刷C写入器的高速缓存ƈ且d器的高速缓存无效?
q表C在q样的系l上Q对于同一变量Q在两个不同处理器上执行的两个线E可能会看到两个不同的|q听h很吓人,但它却很常见。它只是表示在访问其它线E用或修改的数据时Q必遵循某些规则?
Volatile 比同步更单,只适合于控制对基本变量Q整数、布?yu)变量等Q的单个实例的访问。当一个变量被声明?volatileQQ何对该变量的写操作都会绕q高速缓存,直接写入d存,而Q何对该变量的d也都l过高速缓存,直接取自d存。这表示所有线E在M时候看到的 volatile 变量值都相同?
如果没有正确的同步,U程可能会看到旧的变量|或者引起其它Ş式的数据损坏?
5、用锁保护的原子代码?
Volatile 对于保每个U程看到最新的变量值非常有用,但有时我们需要保护比较大的代码片D,如涉及更新多个变量的片段?
同步使用监控器(monitorQ或锁的概念Q以协调对特定代码块的访问?
每个 Java 对象都有一个相关的锁。同一旉只能有一个线E持?Java 锁。当U程q入 synchronized 代码块时Q线E会dq等待,直到锁可用,当它可用Ӟ׃获得q个锁,然后执行代码块。当控制退出受保护的代码块Ӟ卛_达了代码块末或者抛Z没有?synchronized 块中捕获的异常时Q它?yu)׃释放该锁?
q样Q每ơ只有一个线E可以执行受l定监控器保护的代码块。从其它U程的角度看Q该代码块可以看作是原子的,它要么全部执行,要么Ҏ(gu)不执行?
6、简单的同步CZ
使用 synchronized 块可以让(zhn)将一l相xCZ个集合来执行Q而不必担心其它线E中断或看到计算的中间结果。以下示例代码将打印? 0”或? 1”。如果没有同步,它还会打印? 1”(或? 0”,随便(zhn)信不信Q?
public class SyncExample {
private static lockObject = new Object();
private static class Thread1 extends Thread {
public void run() {
synchronized (lockObject) {
x = y = 0;
System.out.println(x);
}
}
}
private static class Thread2 extends Thread {
public void run() {
synchronized (lockObject) {
x = y = 1;
System.out.println(y);
}
}
}
public static void main(String[] args) {
new Thread1().run();
new Thread2().run();
}
}
在这两个U程中都必须使用同步Q以便ɘq个E序正确工作?
7、Java 锁定
Java 锁定合ƈ了一U互斥Ş式。每ơ只有一个线E可以持有锁。锁用于保护代码块或整个Ҏ(gu)Q必记住是锁的w䆾保护了代码块Q而不是代码块本nQ这一点很重要。一个锁可以保护许多代码块或Ҏ(gu)?
反之Q仅仅因Z码块由锁保护q不表示两个U程不能同时执行该代码块。它只表C如果两个线E正在等待相同的锁,则它们不能同时执行该代码?
在以下示例中Q两个线E可以同时不受限制地执行 setLastAccess() 中的 synchronized 块,因ؓ每个U程有一个不同的 thingie 倹{因此,synchronized 代码块受C个正在执行的U程中不同锁的保护?
public class SyncExample {
public static class Thingie {
private Date lastAccess;
public synchronized void setLastAccess(Date date) {
this.lastAccess = date;
}
}
public static class MyThread extends Thread {
private Thingie thingie;
public MyThread(Thingie thingie) {
this.thingie = thingie;
}
public void run() {
thingie.setLastAccess(new Date());
}
}
public static void main() {
Thingie thingie1 = new Thingie(),
thingie2 = new Thingie();
new MyThread(thingie1).start();
new MyThread(thingie2).start();
}
}
8、同步的Ҏ(gu)
创徏 synchronized 块的最单方法是方法声明成 synchronized。这表示在进入方法主体之前,调用者必获得锁Q?
public class Point {
public synchronized void setXY(int x, int y) {
this.x = x;
this.y = y;
}
}
对于普通的 synchronizedҎ(gu)Q这个锁是一个对象,针对它调用Ҏ(gu)。对于静?synchronized Ҏ(gu)Q这个锁是与 Class 对象相关的监控器Q在该对象中声明了方法?
仅仅因ؓ setXY() 被声明成 synchronized q不表示两个不同的线E不能同时执?setXY()Q只要它们调用不同的 Point 实例?setXY() 可同时执行。对于一?Point 实例Q一ơ只能有一个线E执?setXY()Q或 Point 的Q何其?synchronized Ҏ(gu)?
9、同步的?
synchronized 块的语法?synchronized Ҏ(gu)E微复杂一点,因ؓq需要显式地指定锁要保护哪个块。Point 的以下版本等价于前一中昄的版本:
public class Point {
public void setXY(int x, int y) {
synchronized (this) {
this.x = x;
this.y = y;
}
}
}
使用 this 引用作ؓ锁很常见Q但qƈ不是必需的。这表示该代码块与q个cM?synchronized Ҏ(gu)使用同一个锁?
׃同步防止了多个线E同时执行一个代码块Q因此性能上就有问题,即是在单处理器pȝ上。最好在可能最的需要保护的代码块上使用同步?
讉K局部(Z堆栈的)变量从来不需要受C护,因ؓ它们只能被自己所属的U程讉K?
10、大多数cdƈ没有同步
因ؓ同步会带来小的性能损失Q大多数通用c,?java.util 中的 Collection c,不在内部使用同步。这表示在没有附加同步的情况下,不能在多个线E中使用诸如 HashMap q样的类?
文章?a >q里
可参考:
http://www-900.ibm.com/developerWorks/cn/xml/x-injava/index.shtml
http://www-900.ibm.com/developerWorks/cn/xml/x-injava2/index.shtml
l论是:DOM4J是这场测试的莯者,目前许多开源项目中大量采用 DOM4J
其实我认为归根结底就是两U技术:DOM和SAX
DOM是一ơ性把XML读进内存Q构造Document对象Q然后可以以M规则来解析文Ӟ也可以做响应修改Q处理比较灵zR但是DOM比较消耗内存,不能处理太大的文件。主的DOM有JDOMQDOM4JQ?br> SAX是一个事仉动的解析器,是逐句LӞ触发事gQ执行操作。但是它只能解析Q不能对XML文g修改?/p>
下面是一些得到classpath和当前类的绝对\径的一些方法。你可能需要用其中的一些方法来得到你需要的资源的绝对\径?/p>
1.FileTest.class.getResource("")
得到的是当前cFileTest.class文g的URI目录。不包括自己Q?/p>
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/com/test/
2.FileTest.class.getResource("/")
得到的是当前的classpath的绝对URI路径?/p>
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
3.Thread.currentThread().getContextClassLoader().getResource("")
得到的也是当前ClassPath的绝对URI路径?/p>
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
4.FileTest.class.getClassLoader().getResource("")
得到的也是当前ClassPath的绝对URI路径?/p>
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
5.ClassLoader.getSystemResource("")
得到的也是当前ClassPath的绝对URI路径?/p>
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
我推荐用Thread.currentThread().getContextClassLoader().getResource("")来得到当前的classpath的绝对\径的URI表示法?/p>
在Web应用E序中,我们一般通过ServletContext.getRealPath("/")Ҏ(gu)得到Web应用E序的根目录的绝对\径。这P我们只需要提供相对于Web应用E序根目录的路径Q就可以构徏出定位资源的l对路径?br />
注意点:
1.量不要使用相对于System.getProperty("user.dir")当前用户目录的相对\径。这是一颗定时炸弹,随时可能要你的命?/p>
2.量使用URI形式
的绝对\径资源。它可以很容易的转变为URI,URLQFile对象?/p>
3.量使用相对classpath的相对\径。不要用绝对\径。用上面ClassLoaderUtilcȝpublic static URL getExtendResource(String relativePath)Ҏ(gu)已经能够使用相对于classpath的相对\径定位所有位|的资源?/p>
4.l对不要使用编码的l对路径。因为,我们完全可以使用ClassLoadercȝgetResource("")Ҏ(gu)得到当前classpath的绝对\径?/p>
使用编码的l对路径是完全没有必要的Q它一定会让你ȝ很难看!E序无法移植!
如果你一定要指定一个绝对\径,那么使用配置文gQ也比硬~码要好得多Q?/p>
当然Q我q是推荐你用程序得到classpath的绝对\径来D源的l对路径