??xml version="1.0" encoding="utf-8" standalone="yes"?>狠狠久久综合,久久精品成人一区二区三区蜜臀,精品久久中文字幕http://www.aygfsteel.com/jiangshachina/category/26908.html同是Java爱好者,盔R何必曾相识Q?lt;br>    a cup of Java, cheers!zh-cnTue, 22 Apr 2014 11:06:28 GMTTue, 22 Apr 2014 11:06:28 GMT60Javaq发基础实践--死锁(?http://www.aygfsteel.com/jiangshachina/archive/2013/12/29/408180.htmlSha JiangSha JiangSun, 29 Dec 2013 12:19:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2013/12/29/408180.htmlhttp://www.aygfsteel.com/jiangshachina/comments/408180.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2013/12/29/408180.html#Feedback1http://www.aygfsteel.com/jiangshachina/comments/commentRss/408180.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/408180.html
Javaq发基础实践--死锁
本文?a href="http://www.aygfsteel.com/jiangshachina/category/53896.html">Javaq发基础实践pd中的一,介绍了最单的死锁场景Qƈ使用jstack产生的thread dump来查找死锁?2013.12.29最后更?

1. 死锁
Z能够l护U程的安全性,Java提供的锁机制Q但不恰当地使用锁则可能产生死锁。死锁是q发~程中一个无法绕开的问题。只要在一个Q务中使用了一个以上的锁,那么存在死锁的风险?br />死锁产生的直接原因非常简单,即两个线E在怺{待Ҏ所执有的锁?br />
2. 锁顺序死?/span>
在死锁场景中Q最典型的就是锁序死锁Q代码清?是一个很常见的示例?br />
清单1
public class DeadLock {

    
private Object leftLock = new Object();
    
private Object rightLock = new Object();

    
public void leftRight() {
        
synchronized (leftLock) {
            
try {
                TimeUnit.SECONDS.sleep(
3);
            } 
catch (InterruptedException e) {
                e.printStackTrace();
            }

            
synchronized (rightLock) {
                System.out.println(
"leftRight");
            }
        }
    }

    
public void rightLeft() {
        
synchronized (rightLock) {
            
try {
                TimeUnit.SECONDS.sleep(
3);
            } 
catch (InterruptedException e) {
                e.printStackTrace();
            }

            
synchronized (leftLock) {
                System.out.println(
"leftRight");
            }
        }
    }

    
public static void main(String[] args) {
        
final DeadLock deadLock = new DeadLock();

        Thread t1 
= new Thread(new Runnable() {

            @Override
            
public void run() {
                deadLock.leftRight();
            }
        });

        Thread t2 
= new Thread(new Runnable() {

            @Override
            
public void run() {
                deadLock.rightLeft();
            }
        });

        t1.start();
        t2.start();
    }
}

3. Thread Dump
JDK提供了一l命令行工具Q其中就包括jstack。通过jstack可以获取当前正运行的Javaq程的java stack和native stack信息。如果Javaq程崩溃了,也可以通过它来获取core file中的java stack和native stack信息Q以方便我们定位问题?br />Z能够使用jstack去输出目标Javaq程的thread dumpQ首先必要弄清楚在执行清单1的程序时Q该E序的进E号。JDK提供的另一个命令行工具jps可以获取pȝ中所有Javaq程的相关信息?br />在命令行H口中执行命?em>jpsQ即可以得到清单2所C的l果
清单2
C:\Documents and Settings\Administrator>jps
2848
4552 DeadLock
5256 Jps
其中4552是在笔者机器上执行E序DeadLock时所生成Javaq程的进E号?br />然后再执行命?em>jstack 4552Q在W者的机器上就会得到清?所C的l果
清单3
C:\Documents and Settings\Administrator>jstack 
4552
2013-12-29 18:45:41
Full thread dump Java HotSpot(TM) Client VM (
23.25-b01 mixed mode, sharing):

"DestroyJavaVM" prio=6 tid=0x00878800 nid=0xd00 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Thread-1" prio=6 tid=0x02b56c00 nid=0x14ec waiting for monitor entry [0x02fdf000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:
33)
        - waiting to lock <0x22be6598> (a java.lang.Object)
        - locked <0x22be65a0> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
2.run(DeadLock.java:53)
        at java.lang.Thread.run(Thread.java:
724)

"Thread-0" prio=6 tid=0x02b55c00 nid=0x354 waiting for monitor entry [0x02f8f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at concurrency.deadlock.DeadLock.leftRight(DeadLock.java:
19)
        - waiting to lock <0x22be65a0> (a java.lang.Object)
        - locked <0x22be6598> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
1.run(DeadLock.java:45)
        at java.lang.Thread.run(Thread.java:
724)

"Service Thread" daemon prio=6 tid=0x02b34800 nid=0x133c runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread0" daemon prio=10 tid=0x02b13800 nid=0x10fc waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" daemon prio=10 tid=0x02b11c00 nid=0x1424 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x02b10800 nid=0x1100 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=0x02af4c00 nid=0x1238 in Object.wait() [0x02daf000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x22b60fb8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:
135)
        - locked <0x22b60fb8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:
151)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:
189)

"Reference Handler" daemon prio=10 tid=0x02af0000 nid=0x12e8 in Object.wait() [0x02d5f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x22b60da0> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:
503)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:
133)
        - locked <0x22b60da0> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=10 tid=0x02aee400 nid=0x129c runnable

"VM Periodic Task Thread" prio=10 tid=0x02b48000 nid=0x89c waiting on condition

JNI global references: 
117


Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x02af4a3c (object 0x22be6598
, a java.lang.Object),
  which is held by 
"Thread-0"
"Thread-0":
  waiting to lock monitor 0x02af310c (object 0x22be65a0
, a java.lang.Object),
  which is held by 
"Thread-1"

Java stack information for the threads listed above:
===================================================
"Thread-1":
        at concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:
33)
        - waiting to lock <0x22be6598> (a java.lang.Object)
        - locked <0x22be65a0> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
2.run(DeadLock.java:53)
        at java.lang.Thread.run(Thread.java:
724)
"Thread-0":
        at concurrency.deadlock.DeadLock.leftRight(DeadLock.java:
19)
        - waiting to lock <0x22be65a0> (a java.lang.Object)
        - locked <0x22be6598> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
1.run(DeadLock.java:45)
        at java.lang.Thread.run(Thread.java:
724)

Found 
1 deadlock.
在上q输ZQ我们可以很明确地看C个死?br />
"Thread-1":
  waiting to lock monitor 0x02af4a3c (object 0x22be6598
, a java.lang.Object),
  which is held by 
"Thread-0"
"Thread-0":
  waiting to lock monitor 0x02af310c (object 0x22be65a0
, a java.lang.Object),
  which is held by 
"Thread-1"
q且它还标明了程序是在哪个地Ҏ发现了上q死?br />
"Thread-1":
        at concurrency.deadlock.DeadLock.rightLeft(DeadLock.java:
33)
        - waiting to lock <0x22be6598> (a java.lang.Object)
        - locked <0x22be65a0> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
2.run(DeadLock.java:53)
        at java.lang.Thread.run(Thread.java:
724)
"Thread-0":
        at concurrency.deadlock.DeadLock.leftRight(DeadLock.java:
19)
        - waiting to lock <0x22be65a0> (a java.lang.Object)
        - locked <0x22be6598> (a java.lang.Object)
        at concurrency.deadlock.DeadLock$
1.run(DeadLock.java:45)
        at java.lang.Thread.run(Thread.java:
724)

4. 结
死锁产生的直接原因非常简单,即两个线E在怺{待Ҏ所执有的锁。锁序死锁是其中最l典的场景,此外q有动态的锁顺序死锁。虽然表现Ş式有所不同Q但本质上都是两个线E在以不同的序来获取相同锁Ӟ发生了死锁问题?br />使用thread dump可以帮助我们分析死锁产生的原因。除了直接用jstack命o来获取thread dump输出以外QJDKq提供了jvisualvm工具Q它能以可视化的方式展示JavaE序的进E号q导出thread dump?/div>

Sha Jiang 2013-12-29 20:19 发表评论
]]>
Java Concurrent Animated(?http://www.aygfsteel.com/jiangshachina/archive/2013/12/07/407310.htmlSha JiangSha JiangSat, 07 Dec 2013 09:45:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2013/12/07/407310.htmlhttp://www.aygfsteel.com/jiangshachina/comments/407310.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2013/12/07/407310.html#Feedback1http://www.aygfsteel.com/jiangshachina/comments/commentRss/407310.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/407310.html
Java Concurrent Animated
    在最C期的Java Magazine中有一访谈,介绍了一个学习Javaq发~程的动d?a >Java Concurrent Animated。该应用以十分直观的方式展示了Javaq发工具包中的每一个重要组Ӟ降低了学习Javaq发~程的难度?2013.12.07最后更?

Java MagazineQ有多少人已l试用过了你的Java Concurrent Animated应用Q?/span>
GraziQ该应用是在2009q?月被引入的,从那时算P已经有了大约20000的下载量。但考虑到已有约一千万的Java开发者,q个下蝲量才只是开始。按国家区分Q下载最多的分别是美?23%)Q印?14)和中?7%)?/span>
    你可以下载一个可以执行的JAR文gQ然后仅需双击它就可以q行了。该应用是由菜单驱动的,或者也可以使用向上或向下键在不同的囑փ和动M间进行导航。它能运行在诸如WindowsQMacQLinux{等所有的q_上。它要求安装Java SE 6或更高的版本?/span>

Java MagazineQ对q个应用最典型的反馈是什么?
GraziQ大家告诉我q个工具很好用。许多h实Ҏ感到兴奋Q尤其是那些正试囑֐团队教授合适ƈ发技术的老师与领g。Java是最早在核心cd中引入ƈ发的语言之一。在当时Q这是一个很强大的特性,但我们很快就发现一个非怼U的程序员与会写出很糟p的q发代码。进行恰当的q发~程是一件困隄x不可能的事情Q但是如何h们能׃旉ȝ解一些现有的框架Q那么在q行q发~码时所产生潜在错误׃变得极少?/span>
    例如Q去看看Java内存模型。开发者经常忽视Java内存模型Q而像个幸的ȝ一样在~码Q那么他们的E序会不太正常,因ؓJava虚拟?JVM)和服务器可能无法利用到由Java内存模型所提供的优化。由于内核在速度与数量上都有了增长,厂商们期望能够高效地利用到这些内核,然而由于错误的q发理Q本来如期运行的E序却开始遇C一些零星的错误?/span>

Java MagazineQ你是说Q这个应用会以我们所虚构的方式去使开发者们能够更快且直观地掌握Javaq发的原理与实践Q?/span>
GraziQ那是达到这一目的一个有的途径。你知道的,Java Concurrent Animatedq不是一个Flash动画。它是一l可交互的JavaE序Q也卻I每个动画都是真地在用它所要演C的q发lg。在屏幕的右Ҏ一个展CZ码片断的面板Q由于动ȝq行Q它会动态地高亮昄及恢复正在执行的代码?/span>
    让你l你一个例子,q个例子发生在ReadWriteLockq个动画中。ReadWriteLock用于保数据的一致性。它允许不受数量限制的线E去获取读锁Qƈ能ƈ发地对这个锁q行操作。但是,写线E在获取q个锁之前只能等待所有的ȝE执行结束。一旦一个写U程获得了这个锁Q那么其它的ȝE或写线E将无法获取它?/span>
    假设一个写U程正在{待正在执行中的ȝE去释放q个读锁Q但H然一个新的读U程跑过来了。那么谁应该获得q个锁会比较好呢Q这个新的读U程应该跑到写线E前面去吗?毕竟Q如果其它的ȝE已l获得了q个锁,那么新来的读U程Z么要ȝ一个尚在等待中的写U程呢?而这实际上这正是Java 5所q的事儿。但某次我在Java 6上运行这个动LQ我注意到行为发生了改变。即Q随后而来的读U程在获取到q个锁之前可能要{待所有的写线E先释放锁?/span>
    我认个新的行为是一个BUGQ且向ƈ发专家Heinz Kabutz博士提及了此事。博士解释道Q这不是一个错误,而一个特性。如果允许新到的ȝE蟩到正处于{待中的写线E的前面去,q就存在产生U程饥饿条g的高风险。因为,存在一U很大的可能性,可能没有M写线E能获得q个锁,它们永q等待着。这是一个如何用动d警示依赖于JVMq行时版本的U程行ؓ的例子?/span>

Java MagazineQ以动画教程的Ş式来展示Ҏ|在Javaq发~程中有何与众不同吗Q?/span>
GraziQMiller定律教会我们Q我们的大脑在某一时刻能处理的思维的数量是有限的。hcd脑們֐于进行顺序的思维处理Q那么即便我们能够克服n体上的束~,q能够去正确地进行理解,在以后也很难q回臛_去重新构造前面的思维处理。可以肯定地是,如果另一个开发者在以后能深入对其进行研IӞ那么仍然非常难以从原有的思维成果中再ơ捕捉到认知轨迹。这L话,脆弱的代码就会很H然C能正常工作了?/span>
    通过使用框架Q我们不仅将q发~程委托l了创徏和维护该框架的聪明开发者们Q而且qؓ沟通设计时引入了一个词典。所以,我可以说Q?#8220;下面的代码会当作CyclicBarrierL?#8221;Q而h们会明白那是什么意思。通过为java.util.concurrent中的所有组仉引入一个可交互化的动画应用Q开发者们点着鼠标p很方便地他们所探究的功能进行可视化Q理解q些法变得真心单了?/span>

Java MagazineQ你当时正在研究某些直觉Q这些直觉可以帮助更方便地学习ƈ发编E。从开发者的反馈来看Q这些直觉看h是有效的?/span>
GraziQ是的。例如,我前面解释的ReadWriteLock基本功能。读者们可能理解了,也可能没有。现在让我们看看q个与其有关的动画,如图?所C?/span>

    l色U程是读U程Q最上面的白色线E?带着菱Ş头)是一个写U程Q它下面的白色线E是一个新的读U程Q该U程在获取锁之前必须要等待所有的ȝE与写线E执行完毕。如果你点击按钮q观看这些动画,会比通过览J冗的解释性文字去q行理解要简单得多了?/span>

Java MagazineQHeinz Kabutz评论道,Java被构建成能够一ơ性做许多事情Q而这正与q发完全相关。你的学习系l是如何提高E序员的技能,以便他们能降低ƈ发错误的风险?/span>
GraziQ经常地Q当我要努力克服一个ƈ发问题时Q我知道解决Ҏ存在于某个设计模式中,但是哪一个呢Q在开发者探M个正解x案时QJava Concurrent AnimatedZ们提供了一个所有方案的目录Q在Ȁ发出正确Ҏ的过E中Q它扮演着向导的角艌Ӏ?/span>

Java MagazineQ当你管理的团队正在使用Javaq发Qƈ且你和你的团队都x好地ȝ解Javaq发QJava Concurrent Animated有着它的出发炏V是什么导致你使用动画呢,能描qCq个q程吗?
GraziQ我的培训是针对投资部门的服务器端Java应用Q在那里Qƈ发是一个通常都会受到x的问题。交易员们要求gq要低,q样可以保他们在这个需要于一毫秒H口旉内捕捉交易机会的比赛中不会成为失败者。批量处理也要求快速完成,{等。所以我开始看到那些可怕的只写(write-only)lgQ这些组件Z在ƈ发编E挣扎着。我自己也n处其中?/span>
    某天下午Q我正坐在机场内Q将要前往芝加哥ؓ我的团队做一个关于ƈ发的讲演。我正对讲演的PPTq行最后的处理Q那l灯片着重演CZ每一个重要的lg。ؓ了引导我览java.util.concurrent中每个ƈ发组件的状态,我写了一些状态机Q它们展CZ一些供我参考用的简单文本消息。在之前的生涯中Q我曑֜一家互联网创业公司中开发交互式的游戏,所以我懂得许多与动ȝ关的知识。这使我惛_可以PPT替换成一l交互式的动d用,那会更ؓ直观?/span>
    在等飞机的过E中Q我写了一个初步的动画引擎Q然后在我的状态机中调用了q个引擎。到了第二天早晨Q我已经有一个可用的原型E序。多q来Q我一直致力于q个框架Qƈ且吸引了其他专家的徏议。我传递过一份早期版本给Brian GoetzQo人惊讶的是,他ؓ每个动画E序都给Z。我他的所有徏议到吸收C该框架中。在我的W一ơJavaOne讲演中,Kirk Pepperdine加入了进来。他为动d用在真正的PPT中加入描qͼ以便讲演者能C正在讨论的内宏V随后我加上那些描述Q这实非常有用--不只是对讲演者有用,对于l端用户也很有用。Heinz Kabutz也加入了那场讲演Qƈ修改某些动画Q以使它们更为直观?/span>
    在另一演中Q一个很有激情的软g咨询师Oliver Zeigermann指出Q很昄~少了针对ConcurrentHashMap的动甅R我问他是否有兴A献这个动画,随后他添加了那个很有价值的动画E序?/span>

Java MagazineQ你能带着我们q一遍Javaq发工具包中的类吗?q能否解释一下这些动ȝ序是如何使开发者们更易于深入理解这些类Q?/span>
GraziQ好的,但在没有动画E序的情况下实很难办到。让我们看看CyclicBarrierQ它有两个重要的状态,如图2和图3所C,它们展示了一个障和四个成员。在?中,我们可以看到有三个成员已l到了,所以它们被Ll箋前进。图3展示了,一旦第四个成员也到达了Q每个成员又可以向前C?/span>



    q就形象地诠释了障碍的概念,亦即Q在所有成员到N点之前Q每个成员必ȝ待。随着q发lg复杂度的增加--例如Fork/Join的动画,以及那些演示原生的wait和notify机制的动?-使用动画E序的好处就更不肖说了?/span>

Java MagazineQ谈谈在创徏q些动画E序的过E中所遇到的一些挑战?/span>
GraziQ有一些挑战。开始时Q线E被表示成箭头。对于多数ƈ发组Ӟq种表示法是有效的。后来我们必L供一个可视化ҎQ不仅要表示U程Q还要表CBlockingQueue中的对象。所以,我不得不引入一个称之ؓ"_cd(sprite-type)"的概念,然后我们有了一个箭头型的精늱型和一个新?对象"型的_cd。后来,ConcurrentHashMap和AtomicInteger又需要新的精늱型,因ؓ我们试图要对他们的计与交换行ؓq行可视化?/span>
    后面又来了Fork/JoinQ新的挑战就是如何去表现那些完全不同于现有框架所表现的可视化部g。还有一个挑战,即Fork/Join动画需要解决一个实际的问题Q但q个动画应该解决一个什么样的问题呢Q?/span>
    开始时Q我让这个动ȝ序去求Fibonacci数列Q但却行不通。我在这个问题上U结了两天时_直到我认识到Fibonacci数列(Fn+1=Fn+Fn-1)无法高效地ƈ行化Q因为每个值都依赖于它前面的倹{所以,无论你如何试囑֯其实施ƈ行化Q它天生是一个顺序化的计。所以我换成了另一个问?-查找数组中的最大元素,q样好了。在q个动画中,你可以很_地看到如何用一个随机的数列去解册个问?如图4所C??/span>


Java MagazineQ你都在哪里讲演q这些动ȝ序?
GraziQ在JavaOne中讲演过几次Q在其它的许多会议,如奥斯陆中的JavaZoneQ苏黎世的JazoonQ纽U的QConQ以及许多SIG(特别兴趣l?和JUG(Java用户l?中也都讲演过。我喜欢讲演Q我也喜Ƣ周怸界,而Java Concurrent Animated为我提供了一个极好的Zdq两件事情。它总能获得极高的评仗?/span>
    Java Concurrent Animated的讲演提供了一U意识,q且它们也向出席的开发者们展示了下载这一框架的h|而且它还展示了,如果你拥有了框架和灵感启q,学习q发~程会是多么的容易?/span>


Sha Jiang 2013-12-07 17:45 发表评论
]]>
Javaq发基础实践--分而治??http://www.aygfsteel.com/jiangshachina/archive/2013/10/23/405577.htmlSha JiangSha JiangWed, 23 Oct 2013 15:27:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2013/10/23/405577.htmlhttp://www.aygfsteel.com/jiangshachina/comments/405577.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2013/10/23/405577.html#Feedback0http://www.aygfsteel.com/jiangshachina/comments/commentRss/405577.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/405577.html阅读全文

Sha Jiang 2013-10-23 23:27 发表评论
]]>
Javaq发基础实践--退ZQ务II(?http://www.aygfsteel.com/jiangshachina/archive/2013/10/07/404690.htmlSha JiangSha JiangMon, 07 Oct 2013 08:55:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2013/10/07/404690.htmlhttp://www.aygfsteel.com/jiangshachina/comments/404690.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2013/10/07/404690.html#Feedback3http://www.aygfsteel.com/jiangshachina/comments/commentRss/404690.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/404690.html
Javaq发基础实践--退ZQ务II
?a href="http://www.aygfsteel.com/jiangshachina/category/53896.html">本系?/a>?a href="http://www.aygfsteel.com/jiangshachina/archive/2013/09/21/404269.html">上一?/a>中所q的退出ƈ发Q务的方式都是ZJDK 5之前的APIQ本文将介绍使用由JDK 5引入的ƈ发工具包中的API来退ZQ务?2013.10.08最后更?

    在本pd的前一中讲述了三U退出ƈ发Q务的方式--停止U程Q可取消的Q务;中断Q但都是ZJDK 5之前的API。本将介绍由JDK 5引入的java.concurrent包中的Future来取消Q务的执行?br />
1. Future模式
    Future是ƈ发编E中的一U常见设计模式,它相当于是Proxy模式与Thread-Per-Message模式的结合。即Q每ơ都创徏一个单独的U程L行一个耗时的Q务,q且创徏一个Future对象L有实际的d对象Q在来需要的时候再去获取实际Q务的执行l果?br />依然先创Z个用于扫描文件的dFileScannerTaskQ如代码清单1所C,
清单1
public class FileScannerTask implements Runnable {

    
private File root = null;

    
private ArrayList<String> filePaths = new ArrayList<String>();

    
public FileScannerTask(File root) {
        
if (root == null || !root.exists() || !root.isDirectory()) {
            
throw new IllegalArgumentException("root must be directory");
        }

        
this.root = root;
    }

    @Override
    
public void run() {
        travleFiles(root);
    }

    
private void travleFiles(File parent) {
        String filePath 
= parent.getAbsolutePath();
        filePaths.add(filePath);

        
if (parent.isDirectory()) {
            File[] children 
= parent.listFiles();
            
if (children != null) {
                
for (File child : children) {
                    travleFiles(child);
                }
            }
        }
    }

    
public List<String> getFilePaths() {
        
return (List<String>) filePaths.clone();
    }
}
此处的文件扫描Q务,提供了一个getFilePaths()Ҏ以允讔R旉可以取出当前已扫描过的文件的路径(相当于一个Q务快?。然后,创徏一个针对该d的Futurec,如代码清?所C,
清单2
public class FileScannerFuture {

    
private FileScannerTask task = null;

    
public FileScannerFuture(FileScannerTask task) {
        
new Thread(task).start();
        
this.task = task;
    }

    
public List<String> getResult() {
        
return task.getFilePaths();
    }
}
FileScannerFuture持有FileScannerTask的引用,q创Z个独立的U程来执行该d。在d的执行过E中Q应用程序可以在"未来"的某个时d获取一个Q务的快照Q如代码清单3所C,
清单3
public static void main(String[] args) throws Exception {
    FileScannerFuture future 
= new FileScannerFuture(new FileScannerTask(new File("C:")));

    TimeUnit.SECONDS.sleep(
1);
    List
<String> filePaths1 = future.getResult();
    System.out.println(filePaths1.size());

    TimeUnit.SECONDS.sleep(
1);
    List
<String> filePaths2 = future.getResult();
    System.out.println(filePaths2.size());
}

2. 使用q发工具包中的Future实现
    前面所展示的Future实现十分的简陋,没有实际应用的意义。用FileScannerFutureQ应用程序在获取filePathsӞ无法得知其获取的是否为最l结果,x法判断FileScannerTask是否已经完成。而且Q也不能在必要时停止FileScannerTask的执行。毫无疑问,由JDK 5引入的ƈ发工具包肯定会提供此cd用工P如FutureTask。ؓ了用ƈ发工具包中的FutureQ需要修改前q的FileScannerTask实现Q让其实现Callable接口Q如代码清单4所C,
清单4
public class FileScannerTask implements Callable<List<String>> {

    
private File root = null;

    
private List<String> filePaths = new ArrayList<String>();

    
public FileScannerTask(File root) {
        
if (root == null || !root.exists() || !root.isDirectory()) {
            
throw new IllegalArgumentException("root must be directory");
        }

        
this.root = root;
    }

    @Override
    
public List<String> call() {
        travleFiles(root);
        
return filePaths;
    }

    
private void travleFiles(File parent) {
        String filePath 
= parent.getAbsolutePath();
        filePaths.add(filePath);

        
if (parent.isDirectory()) {
            File[] children 
= parent.listFiles();
            
if (children != null) {
                
for (File child : children) {
                    travleFiles(child);
                }
            }
        }
    }

    
public List<String> getFilePaths() {
        
return (List<String>) filePaths.clone();
    }
}
应用E序也要相应的修Ҏ如代码清?所C,使用ExecutorService来提交Q务,q创Z个Future/FutureTask实例?br />
清单5
public static void main(String[] args) {
    ExecutorService executorService 
= Executors.newCachedThreadPool();
    Future
<List<String>> future = executorService.submit(new FileScannerTask(new File("C:")));

    
try {
        List
<String> filePaths = future.get();
        System.out.println(filePaths.size());
    } 
catch (InterruptedException e) {
        e.printStackTrace();
    } 
catch (ExecutionException e) {
        e.printStackTrace();
    }

    executorService.shutdown();
}
此处是调用Future.get()Ҏ来获取Q务的执行l果Q如果Q务没有执行完毕,那么该方法将会被d。该Future实现的好处就是,正常情况下,只有在Q务执行完毕之后才能获取其l果Q以保证该结果是最l执行结果?br />
3. 使用Future取消d
    Future除了定义有可获取执行l果的getҎ(get()以及get(long timeout, TimeUnit unit))Q还定义了三个方法:cancel()QisCancelled()以及isDone()Q用于取消Q务,以及判定d是否已被取消、已执行完毕。如代码清单6所C,
清单6
public interface Future<V> {

    
boolean cancel(boolean mayInterruptIfRunning);
    
boolean isCancelled();
    
boolean isDone();
    
}
其中Qcancel()Ҏ中的boolean参数若ؓtrueQ表C在取消该Q务时Q若执行该Q务的U程仍在q行中,则对其进行中断。如代码清单7所C,若Q务执行超时了Q那么就取消它?br />
清单7
public static void main(String[] args) {
    ExecutorService executorService 
= Executors.newCachedThreadPool();
    Future
<List<String>> future = executorService.submit(new FileScannerTask(new File("C:")));

    
try {
        List
<String> filePaths = future.get(1, TimeUnit.SECONDS);
        System.out.println(filePaths.size());
    } 
catch (InterruptedException e) {
        e.printStackTrace();
    } 
catch (ExecutionException e) {
        e.printStackTrace();
    } 
catch (TimeoutException e) {
        e.printStackTrace();
    } 
finally {
        future.cancel(
true);
    }

    executorService.shutdown();
}
在实际应用中Q取消Q务的原由肯定不仅仅只是超时这么简单,q可能是׃接受C用户的指令。此Ӟ则可能会从另一个独立线E去取消该Q务。除了取消Q务之外,有时q需要取ZQ务中已经生成的部分结果。但Z能够响应d的退出,首先需要修改FileScannerTaskQ得当d被取?中断)Ӟd能够真正的快速停止ƈq回Q如代码清单8所C,
清单8
public class FileScannerTask implements Callable<List<String>> {

    

    
private void travleFiles(File parent) {
        
if (Thread.currentThread().isInterrupted()) {
            
return;
        }

        String filePath 
= parent.getAbsolutePath();
        filePaths.add(filePath);

        
if (parent.isDirectory()) {
            File[] children 
= parent.listFiles();
            
if (children != null) {
                
for (File child : children) {
                    travleFiles(child);
                }
            }
        }
    }

    
}
相应C改应用程序的代码Q如代码清单9所C,
清单9
public static void main(String[] args) {
    ExecutorService executorService 
= Executors.newCachedThreadPool();
    FileScannerTask task 
= new FileScannerTask(new File("C:"));
    
final Future<List<String>> future = executorService.submit(task);
    
    
new Thread(new Runnable() {
        
        @Override
        
public void run() {
            
try {
                TimeUnit.SECONDS.sleep(
1);
            } 
catch (InterruptedException e) {
                e.printStackTrace();
            }
            future.cancel(
true);
        }
    }).start();
    
    
try {
        List
<String> filePaths = future.get();
        System.out.println(filePaths.size());
    } 
catch (InterruptedException e) {
        e.printStackTrace();
    } 
catch (ExecutionException e) {
        e.printStackTrace();
    } 
catch (CancellationException e) {
        List
<String> filePaths = task.getFilePaths();
        System.out.println(
"Partly result: " + filePaths.size());
    }
    
    executorService.shutdown();
}
׃可知Q此处用Future.cancel(true)的本质依然是利用了线E的中断机制?br />
4. 结
    使用Future可以在Q务启动之后的特定时机再去获取d的执行结果。由JDK 5引入的ƈ发工具包中提供的Future实现不仅可以获取d的执行结果,q可以用于取消Q务的执行?/div>

Sha Jiang 2013-10-07 16:55 发表评论
]]>
Javaq发基础实践--退ZQ务I(?http://www.aygfsteel.com/jiangshachina/archive/2013/09/21/404269.htmlSha JiangSha JiangSat, 21 Sep 2013 11:11:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2013/09/21/404269.htmlhttp://www.aygfsteel.com/jiangshachina/comments/404269.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2013/09/21/404269.html#Feedback0http://www.aygfsteel.com/jiangshachina/comments/commentRss/404269.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/404269.html
Javaq发基础实践--退ZQ务I
计划写一?Javaq发基础实践"pdQ算作本人对Javaq发学习与实늚单ȝ。本文是该系列的W一,介绍了退出ƈ发Q务的最单方法?2013.09.25最后更?

在一个ƈ发Q务被启动之后Q不要期望它L会执行完成。由于时间限Ӟ资源限制Q用h作,甚至是Q务中的异?其是运行时异常)Q?..都可能造成d不能执行完成。如何恰当地退ZQ务是一个很常见的问题,而且实现Ҏ也不一而?/span>

1. d
创徏一个ƈ发Q务,递归地获取指定目录下的所有子目录与文件的l对路径Q最后再这些\径信息保存到一个文件中Q如代码清单1所C:
清单1
public class FileScanner implements Runnable {

    
private File root = null;

    
private List<String> filePaths = new ArrayList<String>();

    
public FileScanner1(File root) {
        
if (root == null || !root.exists() || !root.isDirectory()) {
            
throw new IllegalArgumentException("root must be legal directory");
        }

        
this.root = root;
    }

    @Override
    
public void run() {
        travleFiles(root);
        
try {
            saveFilePaths();
        } 
catch (Exception e) {
            e.printStackTrace();
        }
    }

    
private void travleFiles(File parent) {
        String filePath 
= parent.getAbsolutePath();
        filePaths.add(filePath);

        
if (parent.isDirectory()) {
            File[] children 
= parent.listFiles();
            
for (File child : children) {
                travleFiles(child);
            }
        }
    }

    
private void saveFilePaths() throws IOException {
        FileWriter fos 
= new FileWriter(new File(root.getAbsoluteFile()
                
+ File.separator + "filePaths.out"));
        
for (String filePath : filePaths) {
            fos.write(filePath 
+ "\n");
        }
        fos.close();
    }
}

2. 停止U程
有一个很直接Q也很干脆的方式来停止线E,是调用Thread.stop()ҎQ如代码清单2所C:
清单2
public static void main(String[] args) throws Exception {
    FileScanner task 
= new FileScanner(new File("C:"));
    Thread taskThread 
= new Thread(task);
    taskThread.start();

    TimeUnit.SECONDS.sleep(
1);
    taskThread.stop();
}
但是Q地球h都知道Thread.stop()在很久很久之前就不推荐用了。根?a >官方文档的介l,该方法存在着固有的不安全性。当停止U程Ӟ会释放该线E所占有的全部监视锁Q这׃造成受这些锁保护的对象的不一致性。在执行清单2的应用程序时Q它的运行结果是不确定的。它可能会输Z个文Ӟ其中包含部分的被扫描q的目录和文件。但它也很有可能什么也不输出,因ؓ在执行FileWriter.write()的过E中Q可能由于线E停止而造成了I/O异常Q得最l无法得到输出文件?/span>

3. 可取消的d
另外一U十分常见的途径是,在设计之初,我们׃d是可被取消的。一般地Q就是提供一个取消标志或讑֮一个取消条Ӟ一旦Q务遇到该标志或满了取消条gQ就会结束Q务的执行。如代码清单3所C:
清单3
public class FileScanner implements Runnable {

    
private File root = null;

    
private List<String> filePaths = new ArrayList<String>();

    
private boolean cancel = false;

    
public FileScanner(File root) {
        
    }

    @Override
    
public void run() {
        
    }

    
private void travleFiles(File parent) {
        
if (cancel) {
            
return;
        }

        String filePath 
= parent.getAbsolutePath();
        filePaths.add(filePath);

        
if (parent.isDirectory()) {
            File[] children 
= parent.listFiles();
            
for (File child : children) {
                travleFiles(child);
            }
        }
    }

    
private void saveFilePaths() throws IOException {
        
    }

    
public void cancel() {
        cancel 
= true;
    }
}
新的FileScanner实现提供一个cancel标志QtravleFiles()会遍历新的文件之前检该标志Q若该标志ؓtrueQ则会立卌回。代码清?是用新d的应用程序?/span>
清单4
public static void main(String[] args) throws Exception {
    FileScanner task 
= new FileScanner(new File("C:"));
    Thread taskThread 
= new Thread(task);
    taskThread.start();

    TimeUnit.SECONDS.sleep(
3);
    task.cancel();
}
但有些时候用可取消的Q务,q不能快速地退ZQ务。因ZQ务在取消标志之前,可能正处于等待状态,甚至可能被阻塞着。对清单2中的FileScannerE作修改Q让每次讉K新的文g之前先睡?0U钟Q如代码清单5所C:
清单5
public class FileScanner implements Runnable {

    

    
private void travleFiles(File parent) {
        
try {
            TimeUnit.SECONDS.sleep(
10);
        } 
catch (InterruptedException e) {
            e.printStackTrace();
        }

        
if (cancel) {
            
return;
        }

        
    }

    
private void saveFilePaths() throws IOException {
        
    }

    
public void cancel() {
        cancel 
= true;
    }
}
再执行清?中的应用E序Ӟ可能发现dq没有很快速的退出,而是又等待了大约7U钟才退出。如果在查cancel标志之前要先获取某个受锁保护的资源,那么该Q务就会被dQƈ且无法确定何时能够退出。对于这U情况,需要用中断了?/span>

4. 中断
中断是一U协作机Ӟ它ƈ不会真正地停止一个线E,而只是提醒线E需要被中断Qƈ线E的中断状态设|ؓtrue。如果线E正在执行一些可抛出InterruptedException的方法,如Thread.sleep()QThread.join()和Object.wait()Q那么当U程被中断时Q上q方法就会抛出InterruptedExceptionQƈ且中断状态会被重新设|ؓfalse。Q务程序只要恰当处理该异常Q就可以正常地退ZQ务。对清单5再稍作修改,卻I如果d在睡眠时遇上了InterruptedExceptionQ那么就取消d。如代码清单6所C:
清单6
public class FileScanner implements Runnable {

    

    
private void travleFiles(File parent) {
        
try {
            TimeUnit.SECONDS.sleep(
10);
        } 
catch (InterruptedException e) {
            cancel();
        }

        
if (cancel) {
            
return;
        }

        
    }

    
}
同时清?中的应用E序Q此时将调用Thread.interrupt()ҎM断线E,如代码清?所C:
清单7
public static void main(String[] args) throws Exception {
    FileScanner3 task 
= new FileScanner3(new File("C:"));
    Thread taskThread 
= new Thread(task);
    taskThread.start();

    TimeUnit.SECONDS.sleep(
3);
    taskThread.interrupt();
}
或者更q一步,仅用中断状态来控制E序的退出,而不再用可取消的Q?卻I删除cancel标志)Q将清单6中的FileScanner修改成如下:
清单8
public class FileScanner implements Runnable {

    

    
private void travleFiles(File parent) {
        
try {
            TimeUnit.SECONDS.sleep(
10);
        } 
catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        
if (Thread.currentThread().isInterrupted()) {
            
return;
        }

        
    }

    
}
再次执行清单7的应用程序后Q新的FileScanner也能x的退Z。值得注意的是Q因为当sleep()Ҏ抛出InterruptedExceptionӞ该线E的中断状态将又会被设|ؓfalseQ所以必要再次调用interrupt()Ҏ来保存中断状态,q样在后面才可以利用中断状态来判定是否需要返回travleFiles()Ҏ。当Ӟ对于此处的例子,在收到InterruptedException时也可以选择直接q回Q如代码清单9所C:
清单9
public class FileScanner implements Runnable {

    

    
private void travleFiles(File parent) {
        
try {
            TimeUnit.SECONDS.sleep(
10);
        } 
catch (InterruptedException e) {
            
return;
        }

        
    }

    
}

5 结
本文介绍了三U简单的退出ƈ发Q务的ҎQ停止线E;使用可取消Q务;使用中断。毫无疑问,停止U程是不可取的。用可取消的Q务时Q要避免d׃被阻塞而无法及Ӟ甚至永远无法被取消。一般地Q恰当地使用中断是取消Q务的首选方式?/span>


Sha Jiang 2013-09-21 19:11 发表评论
]]>
你所不知道的五g事情--多线E编E??http://www.aygfsteel.com/jiangshachina/archive/2010/11/20/338571.htmlSha JiangSha JiangSat, 20 Nov 2010 15:49:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2010/11/20/338571.htmlhttp://www.aygfsteel.com/jiangshachina/comments/338571.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2010/11/20/338571.html#Feedback5http://www.aygfsteel.com/jiangshachina/comments/commentRss/338571.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/338571.html你所不知道的五g事情--多线E编E?/span>
q是IBM developerWorks?a >5 thingspd文章中的一?/a>Q讲qC关于多线E的一些应用窍门,值得大家学习?2010.11.22最后更?

摘要Q多U程~程不轻松,但它实能帮助理解JVM如何l微地处理不同代码结构。Steven Haines分享的5个窍门会帮助你在处理同步ҎQvolatile变量以及原子cL做出更ؓ合理的决定?br />
    管很少有Java开发者能够忽略多U程~程Q且Javaq_cd支持它,甚至于更的开发者能有时间去深入学习U程。相反,我们只是泛泛地学习线E,如果需要的话,会向我们的工L中添加新的技巧和技术。通过q种Ҏ你可能会构徏且运行好的应用程序,但你q能做得更好。理解Java~译器和JVM的线E特性,可以帮助你编写更高效Q性能更佳的Java代码?br />     ?a >5 thingspd的本期文章中Q我会介l一些用同步方法,volatile变量和原子类{多U程~程的细节方面。我的讨论特别关注在q些E序l构是如何与JVM和Java~译器进行交互的Q以及不同的交互是如何媄响Java应用E序性能的?br />
1. 同步Ҏ与同步块
    你偶会衡量是否同步整个Ҏ调用Q或者只是同步方法中U程安全的子块。在q种情况下,知道Java~译器在何时源代码转化为字节码是有帮助的,它在处理同步Ҏ和同步块时是完全不同的?br />     当JVM在执行同步方法时Q执行线E标识方法的method_infol构设有ACC_SYNCHRONIZED标记Q然后它自动地获取对象的锁,调用ҎQ再释放锁。如果发生了异常Q线E会自动释放锁?br />     另一斚wQ同步一个方法块Q绕开JVM内徏的对获取对象锁和异常处理的支持,q些功能要显式的写在字节码中。如果你读过含有同步块的Ҏ的字节码Q你看到更多的额外操作ȝ理该功能。清?展示了生成同步方法与同步块所产生的调用:

清单1. 两种同步Ҏ
package com.geekcap;

public class SynchronizationExample {
    
private int i;

    
public synchronized int synchronizedMethodGet() {
        
return i;
    }

    
public int synchronizedBlockGet() {
        
synchronizedthis ) {
            
return i;
        }
    }
}

synchronizedMethodGet()Ҏ生成下列字节码:
    0:    aload_0
    
1:    getfield
    
2:    nop
    
3:    iconst_m1
    
4:    ireturn

而下面是synchronizedBlockGet()Ҏ的字节码Q?br />
    0:    aload_0
    
1:    dup
    
2:    astore_1
    
3:    monitorenter
    
4:    aload_0
    
5:    getfield
    
6:    nop
    
7:    iconst_m1
    
8:    aload_1
    
9:    monitorexit
    
10:    ireturn
    
11:    astore_2
    
12:    aload_1
    
13:    monitorexit
    
14:    aload_2
    
15:    athrow

创徏同步块会产生16行字节码Q然而同步方法只q回5行代码?br />
2. ThreadLocal变量
    如果你想Z个类的所有实例维护单个变量实例,你将使用静态类成员变量来实现这一炏V如果你惛_每个U程中维护一个变量的实例Q你用thread- local变量。ThreadLocal变量不同于^常的变量Q在于每个线E有它自q变量初始化实例,通过get()或set()Ҏ可以讉Kq些变量?br />     让我们说Q你正在开发多U程代码q踪器的目的是从你的E序d一地标识每个线E的路径。挑战在于你需要在跨越多个U程的多个类中协调多个方法。没?ThreadLocalQ这是一个很复杂的问题。当一个线E开始执行时Q它生成一个唯一的标C便于在追t器中进行标识,q在在\径中这个唯一标记传给每个Ҏ?br />     使用ThreadLocalQ问题就变得单了。线E在q行的开始时初始化thread-local变量Q然后在各个cȝ各个Ҏ中去讉K它,q就能确保该变量只会在当前执行线E中l护路径信息。当U程执行完毕ӞU程会将它的特定路径传递给一个管理对象,该对象负责维护所有的路径?br />     当你需要基于每个线E来存储变量Ӟ使用ThreadLocal很有意义?br />
3. volatile变量
    我估计一大半Java开发员知道Java语言含有关键字volatile。其中大U只?0%的h知道它的意义Q只有更的人知道如何高效地使用它。简a之,一个变量用volatile关键字进行标识就意味着该变量的值将被不同的U程修改。ؓ了充分理解volatile关键字的功用Q首先就会帮助我们理解线E是如何处理非volatile变量的?br />     Z改进性能QJava语言规范允许JRE在各个线E中l护一份针Ҏ个变量的引用的复本。你能够认ؓq些变量?thread-local"复本cM于缓存,q会帮助U程避免在每ơ需要访问该变量的值时都去查主内存?br />     但考虑下面场景可能会发生的事情Q两个线E都启动了,W一个线E读到变量A的gؓ5Q而第二个U程d变量A的gؓ10。如果变量A已经?变到10了,然后W一个线Eƈ不会意识到这一变化Q所以它会得到A的错误倹{如果变量A被标CؓvolatileQ然后在M时候,某个U程dA的值时Q它都将查询 A的主复本q读到它的当前倹{?br />     如果应用中的变量不会改变Q那么用一个thread-local~存是有意义的。另外,知道volatile关键字能Z做些什么也是很有帮助的?br />
4. volatile对于同步
    如果变量被声明ؓvolatileQ就意味着它会被多个线E所修改。很自然圎ͼ你会希望JRE能ؓvolatile变量以某U方式强制执行同步。幸q地是,当访问volatile变量ӞJRE隐式地提供了同步Q但会伴随一个很大的代hQ读volatile变量是同步的Q写volatile变量也是同步的,但非原子性操作不能怎么做?br />     q就意味着下面的代码不是线E安全的Q?br />
myVolatileVar++;

前面的语句可以写成如下Ş式:
int temp = 0;
synchronize( myVolatileVar ) {
  temp 
= myVolatileVar;
}

temp
++;

synchronize( myVolatileVar ) {
  myVolatileVar 
= temp;
}

    换言之,如果一个volatile变量按上q方法来q行更新Q即先读取|q修改之Q然后再赋|在两个同步操作之_q个l果是非U程安全的。你可以考虑是用同步,q是依赖JRE对volatile变量的自动同步。更好的Ҏ是根据你的用例:如果赋给volatile变量的g靠于它的当前?例如加法操作)Q如果你x作是U程安全的,那就必须使用同步?br />
5. 原子字段更新?/span>
    当在多线E环境中加或减一个原始数据类型时Q用java.util.concurrent包中新添加的原子cM比编写你自己的同步代码块要好得多。原子类保证能以U程安全的方式来执行q些操作Q如加减数|更新|以及d倹{原子类包括 AtomicIntegerQAtomicBooleanQAtomicLongQAtomicLong{等?br />     使用原子cȝ挑战在于所有的cL法,包括getQsetQ以及get-setҎ都是原子化的。这意味着read和write操作不会以同步的方式来修改原子变量的|也不仅仅重要的读-更新-写操作。如果你惛_同步代码的发布能有更好的控制Q解x法就是用原子字D|新器?br />
使用原子更新
    原子字段更新器,如AtomicIntegerFieldUpdaterQAtomicLongFieldUpdater?AtomicReferenceFieldUpdaterQ是用于volatile字段的基本包装器cR在JDK的内部,Javacd在使用q些原子cR但在应用程序中Q它们还未被q泛使用Q你也没有理׃使用它们?br />     清单2展示的示例,是一个类使用原子更新来改变某人正在阅ȝ书:

清单2. Bookc?/strong>
package com.geeckap.atomicexample;

public class Book
{
    
private String name;

    
public Book()
    {
    }

    
public Book( String name )
    {
        
this.name = name;
    }

    
public String getName()
    {
        
return name;
    }

    
public void setName( String name )
    {
        
this.name = name;
    }
}

Bookcd是一个POJO(Plain Old Java Object)Q只有一个字D:name?br />
清单3. MyObject
package com.geeckap.atomicexample;

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 *
 * 
@author shaines
 
*/
public class MyObject
{
    
private volatile Book whatImReading;

    
private static final AtomicReferenceFieldUpdater<MyObject,Book> updater =
            AtomicReferenceFieldUpdater.newUpdater(
                       MyObject.
class, Book.class"whatImReading" );

    
public Book getWhatImReading()
    {
        
return whatImReading;
    }

    
public void setWhatImReading( Book whatImReading )
    {
        
//this.whatImReading = whatImReading;
        updater.compareAndSet( thisthis.whatImReading, whatImReading );
    }
}

    清单3中的MyObjectcL露了whatImReading属性就是你所期望的,该属性有get和setҎQ但setҎ做的一些事情不太一栗不同于单地内部的Book引用赋予一个特定的Book对象(使用清单3中被注释的代码就可以做到q一?Q该CZ使用了一?AtomicReferenceFieldUpdater?br />
AtomicReferenceFieldUpdater
Javadoc对AtomicReferenceFieldUpdater有如下定义:
    一个基于反的工具c,它能Ҏ定类的指定的volatile引用字段q行原子更新。该c被设计用于原子数据l构Q在q种l构中,相同节点的多个引用字D会q行独立地原子更新?br />     在清?中,通过调用AtomicReferenceFieldUpdater的静态方法newUpdaterp创徏它的实例Q该Ҏ要接收三个参敎ͼ
    包含该字D늚对象的类(在这个例子中Q就是MyObject)
    被自动更新的对象的c?br />     被自动更新的字D늚名称

在执行getWhatImReadingҎ获取实际值时没有使用M形式的同步,然而setWhatImReadingҎ的执行则是一个原子操作?br />     清单4证明了如何去使用setWhatImReading()ҎQ以及如何判断变量的D行了正确C改:

清单4. l习原子更新的测试用?/strong>
package com.geeckap.atomicexample;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class AtomicExampleTest
{
    
private MyObject obj;

    @Before
    
public void setUp()
    {
        obj 
= new MyObject();
        obj.setWhatImReading( 
new Book( "Java 2 From Scratch" ) );
    }

    @Test
    
public void testUpdate()
    {
        obj.setWhatImReading( 
new Book(
                
"Pro Java EE 5 Performance Management and Optimization" ) );
        Assert.assertEquals( 
"Incorrect book name",
                
"Pro Java EE 5 Performance Management and Optimization",
                obj.getWhatImReading().getName() );
    }

}

查看资源以学习更多关于原子类的知识?br />
l论
    多线E编EL存在着挑战性,但涉及到Javaq_Q它已经获得了支持去化一些多U程~程d。在本文中,我讨Z你在ZJavaq_~写多线E应用时可能不知道的五g事情Q包括同步方法与同步块的不同之处Q用ThreadLocal变量为每个线E去存储|针对volatile关键字的q泛误解 (包括在需要同步时依赖volatile所产生的危?Q还要地看了一下原子类的复杂之处。查看资源以学习到更多相关知识?br />


Sha Jiang 2010-11-20 23:49 发表评论
]]>
你所不知道的五g事情--java.util.concurrent(W二部分)(?http://www.aygfsteel.com/jiangshachina/archive/2010/06/16/323650.htmlSha JiangSha JiangWed, 16 Jun 2010 03:42:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2010/06/16/323650.htmlhttp://www.aygfsteel.com/jiangshachina/comments/323650.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2010/06/16/323650.html#Feedback0http://www.aygfsteel.com/jiangshachina/comments/commentRss/323650.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/323650.html你所不知道的五g事情--java.util.concurrent(W二部分)
q是Ted Neward?a >IBM developerWorks?a >5 thingspd文章中的一?/a>Q仍然讲qC关于Javaq发集合API的一些应用窍门,值得大家学习?2010.06.17最后更?

摘要Q除了便于编写ƈ发应用的集合API外,java.util.concurrentq引入了其它的预|程序组Ӟq些lg能辅助你在多U程应用中控制和执行U程。Ted Neward再介l了五个来自于java.util.concurrent的Java~程必备H门?br />
    通过提供U程安全Q性能良好的数据结构,q发集合框架使ƈ发编E变得更Ҏ。然而在有些情况下,开发者需要多C步,q要考虑控制?或调节线E的执行。提供java.util.concurrent包的全部原因是Z化多U程~程--事实上正是如此?br />     接着W一部分Q本文介l了多个同步数据l构Q这些数据结构比核心语言基本l构(监视?的层ơ要高,但不会高到将它们圈囿在一个集合类中。一旦知道了q些锁与栓的用途,p径直ȝ了?br />
1. 信号?/strong>

    在有些企业pȝ中,帔R要开发者去控制针对特定资源的请?U程或动?的数量。虽然完全可能试着手工~写q样的调节程序,但用SemaphorecM更容易些Q该cMZ处理对线E的控制Q如清单1所C:

清单1. 使用信号量调节线E?/strong>
import java.util.*;import java.util.concurrent.*;

public class SemApp
{
    
public static void main(String[] args)
    {
        Runnable limitedCall 
= new Runnable() {
            
final Random rand = new Random();
            
final Semaphore available = new Semaphore(3);
            
int count = 0;
            
public void run()
            {
                
int time = rand.nextInt(15);
                
int num = count++;
                
                
try
                {
                    available.acquire();
                    
                    System.out.println(
"Executing " +
                        
"long-running action for " +
                        time 
+ " seconds #" + num);
                
                    Thread.sleep(time 
* 1000);

                    System.out.println(
"Done with #" +
                        num 
+ "!");

                    available.release();
                }
                
catch (InterruptedException intEx)
                {
                    intEx.printStackTrace();
                }
            }
        };
        
        
for (int i=0; i<10; i++)
            
new Thread(limitedCall).start();
    }
}

    虽然上例?0个线E在q行(针对q行SemApp的Javaq程执行jstackE序可以验证q一?Q但只有3个是zd的。另?个线E会被保存v来,直到其中一个信号量计数器被释放出来?准确地说QSemaphorecL持一ơ获取和释放一个以上的被许可线E,但在此处的场景中q么做没有意义?

2. CountDownLatch
    如果q发cSemaphore是被设计为在同一时刻允许"其中"一个线E执行的话,那么CountDownLatch是赛马比赛中的赯门。该cL有所有的U程Q当遇到某个特定条gQ那时CountDownLatch׃一ơ性释攑օ部的U程?br />
清单2. CountDownLatchQ让我们比赛Q?/strong>
import java.util.*;
import java.util.concurrent.*;

class Race
{
    
private Random rand = new Random();
    
    
private int distance = rand.nextInt(250);
    
private CountDownLatch start;
    
private CountDownLatch finish;
    
    
private List<String> horses = new ArrayList<String>();
    
    
public Race(String names)
    {
        
this.horses.addAll(Arrays.asList(names));
    }
    
    
public void run()
        
throws InterruptedException
    {
        System.out.println(
"And the horses are stepping up to the gate");
        
final CountDownLatch start = new CountDownLatch(1);
        
final CountDownLatch finish = new CountDownLatch(horses.size());
        
final List<String> places =
            Collections.synchronizedList(
new ArrayList<String>());
        
        
for (final String h : horses)
        {
            
new Thread(new Runnable() {
                
public void run() {
                    
try
                    {
                        System.out.println(h 
+
                            
" stepping up to the gate");
                        start.await();
                        
                        
int traveled = 0;
                        
while (traveled < distance)
                        {
                            
// In a 0-2 second period of time.
                            Thread.sleep(rand.nextInt(3* 1000);
                            
                            
//  a horse travels 0-14 lengths
                            traveled += rand.nextInt(15);
                            System.out.println(h 
+
                                
" advanced to " + traveled + "!");
                        }
                        finish.countDown();
                        System.out.println(h 
+
                            
" crossed the finish!");
                        places.add(h);
                    }
                    
catch (InterruptedException intEx)
                    {
                        System.out.println(
"ABORTING RACE!!!");
                        intEx.printStackTrace();
                    }
                }
            }).start();
        }

        System.out.println(
"And they're off!");
        start.countDown();        

        finish.await();
        System.out.println(
"And we have our winners!");
        System.out.println(places.get(
0+ " took the gold");
        System.out.println(places.get(
1+ " got the silver");
        System.out.println(
"and " + places.get(2+ " took home the bronze.");
    }
}

public class CDLApp
{
    
public static void main(String[] args)
        
throws InterruptedException, java.io.IOException
    {
        System.out.println(
"Prepping");
        
        Race r 
= new Race(
            
"Beverly Takes a Bath",
            
"RockerHorse",
            
"Phineas",
            
"Ferb",
            
"Tin Cup",
            
"I'm Faster Than a Monkey",
            
"Glue Factory Reject"
            );
        
        System.out.println(
"It's a race of " + r.getDistance() + " lengths");
        
        System.out.println(
"Press Enter to run the race.");
        System.in.read();
        
        r.run();
    }
}

    注意在清?中,CountDownLatch服务于两个目的:首先Q它同时释放所有的U程Q模拟比赛的开始;但之后,另一个CountDownLatch模拟了比赛的l束。一场比赛会有更多的评论Q你可以在比赛的"转弯"?半程"Ҏ加CountDownLatchQ当马匹跑过1/4E,半程?/4E时?br />
3. Executor
    清单1和清?中的例子都遭遇了一个o人非常沮丧的错误Q你被迫要直接地创徏Thread对象。这是一个造成ȝ的方式,因ؓ在有些JVM中,创徏Thread对象是一仉量的工作,所以重用而非创徏新的U程要好得多。然而在另一些JVM中,情况恰恰相反:Thread是非常轻量的,若你需要一个线E,直接创徏它则会好得多。当Ӟ如果Murphy有他自己的方?他经常就是这么做?Q无Z使用哪种ҎQ对于你最l所依赖的某UJavaq_都会是错误的?br />     JSR-166专家l在一定程度上预见Cq种情况。与让Java开发者直接创建Thread实例不同Q他们推荐Executor接口Q这是一个创建新U程的抽象。如果清?所C,Executor允许你自׃必用new操作W去创徏Thread对象Q?br />
清单3. Executor
Executor exec = getAnExecutorFromSomeplace();
exec.execute(
new Runnable() {  });

    使用Excutor的主要缺点与我们使用所有对象工厂所遇到的缺点一P工厂必须来源于某处。不q地是,不同于CLRQJVMq不带有一个标准的VM范围内的U程池?br />     Executorcd是作取Executor实现实例的常用地方,但它只有newҎ(例如Qؓ了创建新的线E池)Q它没有预创建的实例。所以,如果你想创徏q用一个能贯穿于整个程序的Executor实现Q你可以创Z个你自己的Executor实例?或者,在有些情况下Q你可以使用你所选容?q_所提供的Executor实例?

ExecutorServiceQؓ你服?/strong>
    ExecutorService的用处在于你不必关心Thread来自于何处,Executor接口~ZJava开发者可能期望的一些功能,比如启动一个线E,该线E用于生结果,它会以非d方式一直等待,直到l果出现为止?在桌面应用中q是很普通的需求,在这U应用中用户会执行一个需要访问数据库的UI操作Q如果它耗时太长的话Q就可能惌在它完成之前取消这一操作?
    为此QJSR-166的专家们创造一个更为有用的抽象QExecutorService接口Q该接口启动线E的工厂模型化ؓ一个服务,q样p对该服务q行集合化控制了。例如,不对每个d调用一ơexecute()ҎQExecutorService能创Z个Q务的集合Qƈ可返回代表这些Q务未来结果的Future集合?br />
4. ScheduledExecutorServices
    与ExecutorService接口同样优秀Q特定的d需要以计划的Ş式进行执行,例如在特定的旉间隔或在特定的时L行给定的d。这是l承自ExecutorService的ScheduledExecutorService的职责范畴?br />     如果你的目的是创Z?心蟩"命oQ该命o?U钟去"ping"一ơ。ScheduledExecutorService会帮你做到这一点,正如你在清单4中所见的那般单:

清单4. ScheduledExecutorService按计划去"Ping"

import java.util.concurrent.*;

public class Ping
{
    
public static void main(String[] args)
    {
        ScheduledExecutorService ses 
=
            Executors.newScheduledThreadPool(
1);
        Runnable pinger 
= new Runnable() {
            
public void run() {
                System.out.println(
"PING!");
            }
        };
        ses.scheduleAtFixedRate(pinger, 
55, TimeUnit.SECONDS);
    }
}

    怎么P没有操作U程的烦|如果用户惛_消心跻I也不必操心如何去做,前台或后台都没有昄的标记线E;所有的调度l节都留l了ScheduledExecutorService?br />     Z提一下,如果用户惌取消心蟩Q从scheduleAtFixedRate()Ҏq回的会是一个ScheduledFuture实例Q它不仅含有执行l果(如果有的?Q也有一个cancel()Ҏd止该计划d?br />
5. 时Ҏ
    拥有为阻塞操作置一个确定的时控制的能?q样可以避免死?是java.util.concurrentcd相比于旧有ƈ发APIQ如针对锁的监视器,的最大优点之一?br />     q些Ҏ几乎L按int/TimeUnit对的方式q行重蝲Q该int/TimeUnit对用于指C方法在跛_执行q将控制q回l^C前需要等待多长时间。这要求开发者对此做更多的工?-如果没有获得锁,如何进行恢复?--但结果却几乎L正确的:更少的死锁,以及更加生安全的代码?更多关于生񔞮qA的代码,误Michael Nygard的Release It!)

l论
    java.util.concurrent包含有许多更优雅的工P它们Z集合框架Q但更胜之,特别?locks?atomic包中的类。深入挖掘之Q你发现像CyclicBarrierq样的十分有用的控制l构Q甚至于更多?br />     下一ơ,我们步入一个新的主题:你所不知道的五g关于Jar的事情?br />
请关?a href="http://www.aygfsteel.com/jiangshachina/archive/2010/05/24/321683.html">你所不知道的五g事情--java.util.concurrent(W一部分)



Sha Jiang 2010-06-16 11:42 发表评论
]]>
你所不知道的五g事情--java.util.concurrent(W一部分)(?http://www.aygfsteel.com/jiangshachina/archive/2010/05/24/321683.htmlSha JiangSha JiangMon, 24 May 2010 01:00:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2010/05/24/321683.htmlhttp://www.aygfsteel.com/jiangshachina/comments/321683.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2010/05/24/321683.html#Feedback2http://www.aygfsteel.com/jiangshachina/comments/commentRss/321683.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/321683.html你所不知道的五g事情--java.util.concurrent(W一部分)
                                                           --使用q发集合c进行多U程~程
q是Ted Neward?a >IBM developerWorks?a >5 thingspd文章中的一?/a>Q讲qC关于Javaq发集合API的一些应用窍门,值得大家学习?2010.05.24最后更?

    摘要Q编写既要性能良好又要防止应用崩溃的多U程代码实很难--q也正是我们需要java.util.concurrent的原因。Ted Neward向你展示了像CopyOnWriteArrayListQBlockingQueue和ConcurrentMapq样的ƈ发集合类是如何ؓ了ƈ发编E需要而改q标准集合类的?br />
    q发集合API是Java 5的一大新Ҏ,但由于对Annotation和泛型的热捧Q许多Java开发者忽视了q些API。另?可能更真实的?Q因多开发者猜惛_ƈ发集?API肯定很复杂,像d试解决一些问题那P所以开发者们会回避java.util.concurrent包?br />     事实上,java.util.concurrent的很多类q不需要你费很大力p高效地解决通常的ƈ发问题。l看下去Q你p学到 java.util.concurrent中的c,如CopyOnWriteArrayList和BlockingQueueQ是怎样帮助你解军_U程~程可怕的挑战?br />
1. TimeUnit
    java.util.concurrent.TimeUnit本nq不是集合框架类Q这个枚举得代码非常易诅R用TimeUnit能够开发者从与毫U相关的困苦中解脱出来,转而他们自qҎ或API?br />     TimeUnit能与所有的旉单元协作Q范围从毫秒和微U到天和时Q这意味着它能处理开发者可能用到的几乎所有时间类型。还要感谢这个枚丄型声明的旉转换ҎQ当旉加快Ӟ它甚臌l致到把时转换回毫U?br />
2. CopyOnWriteArrayList
    制作数组的干净复本是一Ҏ本极高的操作Q在旉和内存这两方面均有开销Q以至于在通常的应用中不能考虑该方法;开发者常常求助于使用同步?ArrayList来替代前q方法。但q也是一个比较有代h的选项Q因为当每次你遍历访问该集合中的内容Ӟ你不得不同步所有的ҎQ包括读和写Q以保内存一致性?br />     在有大量用户在读取ArrayList而只有很用户对其进行修改的q一场景中,上述Ҏ成本l构变得~慢?br />     CopyOnWriteArrayList是解决q一问题的一个极好的宝贝工具。它的Javadoc描述刎ͼArrayList通过创徏数组的干净复本来实现可变操?dQ修改,{等)Q而CopyOnWriteArrayList则是ArrayList的一?U程安全"的变体?br />     对于M修改操作Q该集合cM在内部将其内容复制到一个新数组中,所以当ȝ戯问数l的内容时不会招致Q何同步开销(因ؓ它们没有对可变数据进行操??br />     本质上,创徏CopyOnWriteArrayList的想法,是出于应对当ArrayList无法满我们要求时的场景Q经常读Q而很写的集合对象,例如针对JavaBean事g的Listener?br />
3. BlockingQueue
    BlockingQueue接口表明它是一个QueueQ这意味着它的元素是按先进先出(FIFO)的次序进行存储的。以特定ơ序插入的元素会以相同的ơ序被取?-但根据插入保证,M从空队列中取出元素的试都会堵塞调用U程直到该元素可被取出时为止。同样地QQ何向一个已满队列中插入元素的尝试将会堵塞调用线E直到该队列的存储空间有IZ时ؓ止?br />     在不需要显式地x同步问题Ӟ如何由一个线E聚集的元素"交给"另一个线E进行处理呢QBlockingQueue很灵巧地解决了这个问题。Java Tutorial中Guarded Blocks一节是很好的例子。它使用手工同步和wait()/notifyAll()Ҏ创徏了一个单?single-slot)受限~冲Q当一个新的元素可被消费且当该点已l准备好被一个新的元素填充时Q该Ҏ׃在线E之间发Z受?详情误Guarded Blocks)
    管教程Guarded Blocks中的代码可以正常工作Q但它比较长Q有些凌乱,而且完全不直观。诚Ӟ在Javaq_的早期时代,Java开发者们不得不;但现在已l是 2010q了--问题已经得到改进Q?br />     清单1展示的程序重写了Guarded Blocks中的代码Q其中我使用ArrayBlockingQueue替代了手工编写的Drop?br />
清单1. BlockingQueue

import java.util.*;
import java.util.concurrent.*;

class Producer
    
implements Runnable
{
    
private BlockingQueue<String> drop;
    List
<String> messages = Arrays.asList(
        
"Mares eat oats",
        
"Does eat oats",
        
"Little lambs eat ivy",
        
"Wouldn't you eat ivy too?");
        
    
public Producer(BlockingQueue<String> d) { this.drop = d; }
    
    
public void run()
    {
        
try
        {
            
for (String s : messages)
                drop.put(s);
            drop.put(
"DONE");
        }
        
catch (InterruptedException intEx)
        {
            System.out.println(
"Interrupted! " +
                
"Last one out, turn out the lights!");
        }
    }    
}

class Consumer
    
implements Runnable
{
    
private BlockingQueue<String> drop;
    
public Consumer(BlockingQueue<String> d) { this.drop = d; }
    
    
public void run()
    {
        
try
        {
            String msg 
= null;
            
while (!((msg = drop.take()).equals("DONE")))
                System.out.println(msg);
        }
        
catch (InterruptedException intEx)
        {
            System.out.println(
"Interrupted! " +
                
"Last one out, turn out the lights!");
        }
    }
}

public class ABQApp
{
    
public static void main(String[] args)
    {
        BlockingQueue
<String> drop = new ArrayBlockingQueue(1true);
        (
new Thread(new Producer(drop))).start();
        (
new Thread(new Consumer(drop))).start();
    }
}

ArrayBlockingQueue也崇?公^"--x味着Q它能给予读和写U程先进先出的访问次序。该Ҏ可能是一U更高效的策略,但它也加大了造成U程饥饿的风险?是_当其它读U程持有锁时Q该{略可更高效地允许读U程q行执行Q但q也׃产生ȝE的帔R写线EL无法执行的风?
    BlockingQueue也支持在Ҏ中用时间参敎ͼ当插入或取出元素Z问题ӞҎ需要返回以发出操作p|的信P而该旉参数指定了在q回前应该阻塞多长时间?br />
4. ConcurrentMap
    Map有一些细微的q发BugQ会使许多粗心的Java开发者误入歧途。ConcurrentMap则是一个简单的军_Ҏ?br />     当有多个U程在访问一个MapӞ通常在储存一个键/值对之前通常会用方法containsKey()或get()ȝ定给出的键是否存在。即使用同步的MapQ某个线E仍可在处理的过E中潜入其中Q然后获得对Map的控制权。问题在于,在get()Ҏ的开始处获得了锁Q然后在调用Ҏput()去重新获得该锁之前会先释攑֮。这导致了竞争条gQ两个线E之间的竞争Q根据哪个线E先执行Q其l果不相同?br />     如果两个U程在同一时刻调用一个方法,一个测试键是否存在Q另一个则|入新的?值对Q那么在此过E中Q第一个线E的值将会丢失。幸q地是,ConcurrentMap接口支持一l额外的ҎQ设计这些方法是Z在一个锁中做两g事情Q例如,putIfAbsent()首先q行试Q之后只有当该键q未存储到Map中时Q才执行|入操作?br />
5. SynchronousQueues
    ҎJavadoc的描qͼSynchronousQueue是一个很有趣的创造物Q?br />     一个阻塞队列在每次的插入操作中必须{等另一U程执行对应的删除线E,反之亦然。同步队列ƈ没有M内部的存储空_一个都没有?br />     本质上,SynchronousQueue是之前提及的BlockingQueue的另一U实现。用ArrayBlockingQueue利用的阻塞语义,SynchronousQueuel予我们一U极轻量U的途径在两个线E之间交换单个元素。在清单2中,我用SynchronousQueue替代 ArrayBlockingQueue重写了清?的代码:

清单2 SynchronousQueue
import java.util.*;
import java.util.concurrent.*;

class Producer
    
implements Runnable
{
    
private BlockingQueue<String> drop;
    List
<String> messages = Arrays.asList(
        
"Mares eat oats",
        
"Does eat oats",
        
"Little lambs eat ivy",
        
"Wouldn't you eat ivy too?");
        
    
public Producer(BlockingQueue<String> d) { this.drop = d; }
    
    
public void run()
    {
        
try
        {
            
for (String s : messages)
                drop.put(s);
            drop.put(
"DONE");
        }
        
catch (InterruptedException intEx)
        {
            System.out.println(
"Interrupted! " +
                
"Last one out, turn out the lights!");
        }
    }    
}

class Consumer
    
implements Runnable
{
    
private BlockingQueue<String> drop;
    
public Consumer(BlockingQueue<String> d) { this.drop = d; }
    
    
public void run()
    {
        
try
        {
            String msg 
= null;
            
while (!((msg = drop.take()).equals("DONE")))
                System.out.println(msg);
        }
        
catch (InterruptedException intEx)
        {
            System.out.println(
"Interrupted! " +
                
"Last one out, turn out the lights!");
        }
    }
}

public class SynQApp
{
    
public static void main(String[] args)
    {
        BlockingQueue
<String> drop = new SynchronousQueue<String>();
        (
new Thread(new Producer(drop))).start();
        (
new Thread(new Consumer(drop))).start();
    }
}

上述实现看v来几乎相同,但该应用E序已新加了一个好处,在这个实CQ只有当有线E正在等待消Ҏ个元素时QSynchronousQueue才会允许该元素插入到队列中?br /> 实跉|式来看,SynchronousQueuecM于Ada或CSP{语a中的"交会通道(Rendezvous Channel)"。在其它环境中,有时候被UCؓ"q接"?br />
l论
    当Javaq行时类库预先已l提供了方便使用的等LӞZ么还要费力地向集合框架中引入q发呢?本系列的下一文章将探烦 java.util.concurrent命名I间的更多内宏V?br />
请关?a href="http://www.aygfsteel.com/jiangshachina/archive/2010/06/16/323650.html">你所不知道的五g事情--java.util.concurrent(W二部分)



Sha Jiang 2010-05-24 09:00 发表评论
]]>
使用Callableq回l果(?http://www.aygfsteel.com/jiangshachina/archive/2008/05/31/204007.htmlSha JiangSha JiangSat, 31 May 2008 14:24:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2008/05/31/204007.htmlhttp://www.aygfsteel.com/jiangshachina/comments/204007.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2008/05/31/204007.html#Feedback0http://www.aygfsteel.com/jiangshachina/comments/commentRss/204007.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/204007.html使用Callableq回l果
    本文是Sun官方以Blog形式发布的Java核心技术窍?JavaCoreTechTip)中的一个。本文主要介l了Callable及其相关接口和类的用,幅不长且易于理解,故翻译在了此处,怿对于准备或刚接触java.util.concurrent的朋友会有所帮助?2008.05.31最后更?

    自从Javaq_的最开始,Runnable接口已存在了。它允许你定义一个可qE完成的d。如大多Ch所已知的那P它只提供了一个runҎQ该Ҏ既不接受M参数Q也不返回Q何倹{如果你需要从一个未完成的Q务中q回一个|你就必须在该接口之外使用一个方法去{待该Q务完成时通报的某U消息。例如,下面的示例就是你在这U情景下可能做的事情Q?br />     Runnable runnable = ...;
    Thread t = new Thread(runnable);
    t.start();
    t.join();
    String value = someMethodtoGetSavedValue()
严格来说Q上qC码ƈ无错误,但现在可用不同的ҎdQ这要感谢J2SE 5.0引入的Callable接口。不同于Runnable接口拥有runҎQCallable接口提供的是callҎQ该Ҏ可以q回一个Object对象Q或可返回Q何一个在泛型化格式中定义了的特定cd的对象?br />     public interface Callable<V> {
       V call() throws Exception;
    }
因ؓ你不可能把Callable对象传到Thread对象L行,你可换用ExecutorService对象L行Callable对象。该服务接受Callable对象Qƈl由submitҎL行它?br />     <T> Future<T> submit(Callable<T> task)
如该Ҏ的定义所C,提交一个Callable对象lExecutorService会返回一个Future对象。然后,Future的getҎ会dQ直CQ务完成?br />     Z证明q一点,下面的例子ؓ命o行中的每个词都创Z个单独的Callable实例Q然后把q些词的长度加v来。各个Callable对象只是计它自己的词的长度之和。Futures对象的Set集合被保存以便从中获得计算用的倹{如果需要保持返回值的序Q则可换用一个List对象?/span>
import java.util.*;
import java.util.concurrent.*;

public class CallableExample {

    
public static class WordLengthCallable
            
implements Callable {
        
private String word;
        
public WordLengthCallable(String word) {
            
this.word = word;
        }
        
public Integer call() {
            
return Integer.valueOf(word.length());
        }
    }

    
public static void main(String args[]) throws Exception {
        ExecutorService pool 
= Executors.newFixedThreadPool(3);
        Set
<Future<Integer>> set = new HashSet<Future&lg;Integer>>();
        
for (String word: args) {
            Callable
<Integer> callable = new WordLengthCallable(word);
            Future
<Integer> future = pool.submit(callable);
            set.add(future);
        }
        
int sum = 0;
        
for (Future<Integer> future : set) {
            sum 
+= future.get();
        }
        System.out.printf(
"The sum of lengths is %s%n", sum);
        System.exit(sum);
    }
}
WordLengthCallable保存了每个词q用该词的长度作ؓcallҎ的返回倹{这个值可能会q儿时间去生成Q不q在q个例子中,可以立即知道它?callҎ的唯一要求是这个D在callҎ的结֤q回。当Future的getҎE后被调用时Q如果Q务运行得很快的话QFuture会自动得到q个?如同本例的情?Q否则将一直等到该值生成完毕ؓ止。多ơ调用getҎ不会Dd从该U程q回。因E序的目的是计划所有字的长度之和,它不会强令Callabledl束。如果最后一个Q务在前三个Q务之前完成,也是没错的。对Future的getҎ的第一ơ调用将只会{待Set中第一个Q务结束,而不会阻塞其它的d分别执行完毕。它只会{待当次U程或Q务结束。这个特定的例子使用固定数线E池来生ExecutorService对象Q但其它有效的方法也是可行的?br />     关于执行器和U程池用法的更多信息Q请见Java Tutorial?a >Executors一节。SwingWorkercL另一个用Future的Runnable对象的例子,管有些微不同之处。更多信息请见Java Tutorial?a >Worker Threads and SwingWorker一节?br />


Sha Jiang 2008-05-31 22:24 发表评论
]]>
Java Tutorials -- Concurrency(?http://www.aygfsteel.com/jiangshachina/archive/2007/10/28/156522.htmlSha JiangSha JiangSun, 28 Oct 2007 11:51:00 GMThttp://www.aygfsteel.com/jiangshachina/archive/2007/10/28/156522.htmlhttp://www.aygfsteel.com/jiangshachina/comments/156522.htmlhttp://www.aygfsteel.com/jiangshachina/archive/2007/10/28/156522.html#Feedback5http://www.aygfsteel.com/jiangshachina/comments/commentRss/156522.htmlhttp://www.aygfsteel.com/jiangshachina/services/trackbacks/156522.html阅读全文

Sha Jiang 2007-10-28 19:51 发表评论
]]>
վ֩ģ壺 ˷| | | | ͼ| н| | | | | | Ӧñر| »| ɽ| ɽ| ƽ| | | | | | ϳ| ƽ| | | | ԭ| | | | | ÷| | | | | ʩ| ˫| | | |