-
Java程序开发中有大量的可复用资源,可复用的公用类;有很多中间件已经帮助我们解决了多线程的问题,所以很多开发人员是不需要深入的涉及到这个话题的,而要自己去开发一个服务端的应用的时候,多线程的编程、调试、发布、问题跟踪就变得无可避免了。
多线程编程需要涉及到两个方向,一个是使用Java语言进行程序设计,必须了解语言本身对于线程的支持和其编程模型;另外一个是运行时的运行状况,更多的是基于现有的硬件、先有的操作系统的配置问题。所有的应用都必须运行一定的硬件配置环境、一定的操作系统之上,所以线程的运行时状态无可避免的要在应用设计阶段进行考虑了。
1.对于共享可变数据的互斥(什么时候使用关键字synchronized):Java虚拟机通过对象锁来实现互斥,达到多个线程在同一个共享数据上独立而互不干扰地工作。
private int sequence = 0;
public synchronized int getSequence(){
return sequence++;
}
线程间通讯,保证共享对象对于多线程访问是从一种一致的状态跃迁到另外一种一致的状态。
public class Worker implements Runnable{
private boolean running = false;
public void run(){
while(isRunning()){
//
}
}
public synchronized boolean isRunning(){
return this.running;
}
public synchronized void stop(){
this.running = false;
}
public synchronized void startRequest(){
this.running = true;
}
}
2.协作(什么时候使用wait和notify):主要是用于多线程为了同一个目标而共同协作性的工作,应用需要设计多线程的协作工作机制。一般性地是,线程需要反复检查某一个数据结构,在等待某些条件的发生,又避免忙等(busy-wait)的时候。
使用wait()是需要仔细阅读以下javadoc了,wait(0)的情况很特殊:线程一直处于等待,直到被唤醒(notify()或者notifyAll())。
private Object monitor = new Object();
public void run(){
synchronized(monitor){
while(){
try{
obj.wait()
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Java使用的同步机制是监视器,为了更好的使用同步机制,就需要虚拟机是怎么使用监视器的机制的?
Java监视器主要分成了三个区域,入口区、监视区、等待区,所有进入到监视器开始处的线程首先都是进入到入口去,(可能阻塞)等待成为监视区的持有者;监视区域同时只能被一个线程持有并执行,只有当一个线程执行完了监视区域动作(该线程将释放监视区域并推出监视器)或者执行了等待命令(该线程将释放监视区域进入到等待区,直到执行了唤醒命令才能重新持有监视区域)才能释放监视区域;只有那些持有监视区域的线程执行了等待命令之后就会进入到等待区。所以基本可以了解了监视区域的各个功能、线程进出的时机动作。而且分析互斥和协作情况下线程和监视器的工作状态基本也就清晰了。
1.互斥情况下,多线程将会在等待区阻塞的等待持有监视区域,因为同时只会有一个线程执行监视区域(代码即指令),监视区域主要是共享数据或者共享资源。(例外就是虚拟机实现不是基于时间片的,那么监视器就会用来协调多线程的执行策略,将不仅仅是共享数据或者共享资源了。)
2.协作情况下,监视器主要协调多个线程之间共同工作,即是,一个已经持有监视区域的线程,通过执行等待命令,释放监视区域进入到等待区,那么该线程阻塞并一直持续暂停状态,只有监视区域持有线程执行了唤醒该线程命令并释放监视区域之后该线程才能重新持有监视区域,直到该线程再次释放监视区域。
运行阶段,Java线程的线程模型又是什么样的呢,究竟需要应用设计开发人员需要注意什么呢?
这主要涉及到Java的内存模型(Memory Model)、JVM实现等,其中我正在使用的虚拟机是Sun基于Solaris系统的,其线程模型参考《Threading》。Java的线程在Java2都是操作系统的线程,并没有了"green threads"的概念了,每一个线程的申请在向JVM申请资源的同时也是在向操作系统申请资源,对于各家JVM在不同的操作系统之上的thread stack size大小也有一些差别,其中Sun JVM可以通过-XX:ThreadStackSize(-Xss)参数进行设置(在默认情况下,"Thread Stack Size (in Kbytes). (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.]").
在我们设计并发要求比较高的服务端应用的时候,线程将会变得相当宝贵了,而且就针对操作系统而言,一个进程所能申请的线程的数量也是限制的,所以如何使用和调度多线程是一个重要的环节。在系统运行阶段,进行调优的时候不可避免的要面对多线程的资源相关的几个关注点:thread stack size、thread local heap、garbage collection affects、intimate shared memory。
进行多线程的设计编码,要极力追求简洁原则,尽力将多线程的调度和编码和业务相关的逻辑进行解耦,这样多线程处理模块被抽象出来,可复用度变高,对于分析、调试、问题跟踪多线程的设计编码就不再变得臃肿复杂;避免复杂、过多的条件判断等待、wait-notify,线程意外退出或者形成死锁。
在今天的编程生活中,我们也要面对和解决多线程编程的调试、单元测试、跟踪等方面的问题。解决这些问题也是我们的乐趣之一:)
参考:
《Effective Java 中文版》
《深入Java虚拟机》
http://java.sun.com/docs/hotspot/threads/threads.html
http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
http://www.theserverside.com/tt/knowledgecenter/knowledgecenter.tss?l=ConcurrencyTestingJavaApps -
五一假期,老大结婚,一帮兄弟从各地感到郑州,一路旅行,很多朋友、同学很久没有见面,大家畅所欲言,把酒言欢,嬉笑怒骂,十分尽兴。旅途中重读了《The Secrets of Consulting》许多章节,书中很多做事的方法和原则,值得思考和品味。
1.“和我一样,维吉尼亚也很喜欢比喻,并且热衷于从各种地方--比如弗兰克.鲍姆的《绿野仙踪》--收集这些比喻。” 比喻是一种很好的表达的手段,通过类比和联想是很容易使人基于已知的世界去认识未知的世界的,而且往往很是深刻的。在这本书中看到作者是善于运用比喻的, 收集了很多比喻的。作者的工具箱中的所有物体都是现实世界中的实物,确能够被作者引申来说明一系列抽象的原则、远离、方法。
2. 《The Secrets of Consulting》中作者多次运用萨特的三个通用问题来分析问题的:
把问题分解成三个部分:自己、他人以及背景环境。在把自己作为研究焦点时,
- 我怎样到达这里的?(过去)
- 我在这里感觉如何?(现在)
- 我希望发生什么?(将来)
-
粗粗的读完《金字塔原理-----思考、写作与制作图表的逻辑》第一个部分。第一部分分为五章,主要介绍的是:写作的逻辑。如同本文所要讲述的思想一样,第一部分显得的简单而有强烈的逻辑关系。首先简述为什么要选择金字塔结构,是人类思考方式的局限性、一般性,思维的一般惯性:自上而下组织思想;自下而上思考。然后讲叙了金字塔结构的一般原则:疑问/回答式对话的纵向关系结构、演绎或者归纳逻辑的横向关系结构、讲故事式的序言结构。接着讲述了构造金字塔结构的一般方法:自上而下法;自下而上法;注意事项。既然方法已经讲叙了,所谓“万事开头难”,切题即如何写序言变得异常重要,接下来的一章就是关注序言部分的具体写法。介绍了为什么、是什么、怎么做、怎么开始,最后一章介绍了演绎和归纳的区别,意在突出如何将一个一个的思想“点”联系在一些形成逻辑关系,即是演绎和归纳。
看完也有一丝丝小学学语文的感觉,其实本身就是一个方法论的问题。
读完第一章节之后,我有一种模糊的感觉,写作和程序设计之间似乎有很多很多相通的地方,一篇能将思想简单而清楚的讲出来的文章才是好文章,程序设计更是需要简单清晰的。无论写作,还是程序设计,都需要搞清楚问题,搞清楚复杂性,搞清楚如何简单化等等。
以下是摘抄或者评注:
一个人的思维不能仅仅是线性的、一维的。
读者必然会将所读到的思想进行归类概括,以便记住这些思想。如果作者传达给读者的思想事先已经经过归类和概括,并且按自上而下的顺序表述出来,读者就能更容易的理解作者所表述的思想。这就是所说的“条理清楚”.
“因为你总是要不断地对思想进行归类和概括,直到没有可与之关联的思想可继续概括,因此,你写的每一篇文章的结构都必定只支持一个思想,即概括了所有各组思想的单一思想。”
“大多数人刚坐下来开始写作时,可能对他们想要表达的思想还只有一个模糊的想法,甚至根本不知如何下笔。在你不得不用话语或文字将你的思想用符号表示出来之前,你很可能无法准确地了解自己的思想。甚至连你认为已经构思好的第一个思想,写出来可能都不是十分准确。”
“为什么我们可以肯定一定会感兴趣?因为这种纵向联系迫使读者按照你的思想做出符合逻辑的反应。”
自上而下组织思想
自下而上思考
金字塔的子结构
纵向关系:不断地按照“引起读者疑问并回答疑问”的模式,一环扣一环如同波浪,直到读者不会再对新的表述提出任何疑问为止。
横向关系:保证一定的逻辑性,具备明确的归纳或者演绎关系。
序言结构:问题的起源和发展必然以讲故事的形式出现,因此也应当按照典型的讲故事模式发展。就是说,开头应向读者说明“情境(Situation)”的时间和地点。在这一“情境”中应当发展了某件事情称为“冲突(Complication)”,使读者提出(或将使读者提出)你的文章中将要回答 (Answer)的“疑问(Question)”。
作者在谈论“初学者注意事项”,所讨论的一些问题也是平时思维、做事等的一些通病,让人能觉察不仅仅是在写作上。
“文如其人”,写出来的东西完全是一个人思想的映像,写出来的东西透出的是一个人如何思考的。 -
2007-07-31
"What is the crazy" - [读书]
James Gosling在他May 08,2004的Blog的帖子:《The world needs more crazy people》谈到了一些做事的原则,可以作为思考的引子;更要警醒、反省、鼓励自己。
"Most real innovation is done by crazy people doing crazy things. The keys are:
* Learn all you can before you go adventuring.
* Don't be afraid to make mistakes.
* Only make new mistakes.
* Keep your eyes open.
* Don't just look straight ahead: develop your peripheral vision.
* It's the things that go in unexpected directions are the most important." -
最近在搞一个培训的文档的评审,步骤大约是:
1.有一个Session Topic;
2.讲师先要围绕这个Topic写一个大纲,主要是大约是将Topic拆分若干细节分支;
3.评审PPT等文档;
如何对这样的文档进行评审,因为文档只是第一步,也是讲师能否讲这个Topic讲好的关键,所以就开始想如何保证讲师的培训质量,如何保证评审的质量,如何尽量能够促使讲师讲某一个Topic的广度和深度展现给audient呢。
我的思路大约是:
从行业角度看,大家一般讨论这个Topic的角度;
从audient看,我们希望他们能接收到什么信息,他们自身提高中需要什么信息;
从讲师来看,能够给Topic带了什么special的东西;
在我读一个讲稿的时候,我希望我的第一感觉,感觉到一个明显的主线,知道这个讲稿在究竟要讲些什么;能够有一个完整的概念模型,简单易懂,这样便于大家理解;然后能够看到细节性的分析和讲解,就是深入的内容。觉得既要有葡萄蜜饯,也要有果酱颗粒,葡萄蜜饯不至于太突兀,通用的信息让大家理解起来容易,有一种背靠着行业的味道;对于我而言,我更加希望能够看到更多的个人理解的东西,更多的果酱颗粒,会带来思考的地方,带来讨论的地方,往往也是启迪人的地方。希望看多一些specail的地方,希望看到许多兴奋点。
附:果酱和葡萄蜜饯来源于《The Secrets of Consulting》
“只要还有果酱,草莓酱就永远都不会被涂抹得过薄。”
“永远不会有人抱怨葡萄蜜饯。”









