JAVA编程:由临盆者/消耗者成绩看JAVA多线程仓酷云
你精通任何一门语言就最强大。现在来看,java的市场比C#大,C#容易入手,比较简单,java比较难临盆者消耗者成绩是研讨多线程程序时绕不开的成绩,它的形貌是有一块临盆者和消耗者共享的有界缓冲区,临盆者往缓冲区放进产物,消耗者从缓冲区取走产物,这个历程能够无停止的实行,不克不及因缓冲区满临盆者放不进产物而停止,也不克不及因缓冲区空消耗者无产物可取而停止。办理临盆者消耗者成绩的办法有两种,一种是接纳某种机制坚持临盆者和消耗者之间的同步,一种是在临盆者和消耗者之间创建一个管道。前一种有较高的效力而且可把持性较好,对照经常使用,后一种因为管道缓冲区不容易把持及被传输数据对象不容易封装等缘故原由,对照罕用。同步成绩的中心在于,CPU是定时间片轮询的体例实行程序,我们没法晓得某一个线程是不是被实行、是不是被抢占、是不是停止等,因而临盆者完整大概当缓冲区已满的时分还在放进产物,消耗者也完整大概当缓冲区为空时还在掏出产物。如今同步成绩的办理办法通常为接纳旌旗灯号大概加锁机制,即临盆者线程当缓冲区已满时保持本人的实行权,进进守候形态,并关照消耗者线程实行。消耗者线程当缓冲区已空时保持本人的实行权,进进守候形态,并关照临盆者线程实行。如许一来就坚持了线程的同步,并制止了线程间相互守候而进进逝世锁形态。JAVA言语供应了自力于平台的线程机制,坚持了”writeonce,runanywhere”的特征。同时也供应了对同步机制的优秀撑持。在JAVA中,一共有四种办法撑持同步,个中三个是同步办法,一个是管道办法。1.办法wait()/notify()2.办法await()/signal()3.堵塞行列办法BlockingQueue4.管道办法PipedInputStream/PipedOutputStream上面我们看各个办法的完成:1.办法wait()/notify()wait()和notify()是根类Object的两个办法,也就意味着一切的JAVA类城市具有这个两个办法,为何会被如许计划呢?我们能够以为一切的对象默许都具有一个锁,固然我们看不到,也没有举措间接操纵,但它是存在的。wait()办法暗示:当缓冲区已满或空时,临盆者或消耗者线程中断本人的实行,保持锁,使本人处于守候形态,让另外一个线程入手下手实行;notify()办法暗示:当临盆者或消耗者对缓冲区放进或掏出一个产物时,向另外一个线程收回可实行关照,同时保持锁,使本人处于守候形态。上面是一个例子代码:<br>importjava.util.LinkedList;
<br>
<br>
<br>publicclassSycn1...{
<br>privateLinkedList<Object>myList=newLinkedList<Object>();
<br>privateintMAX=10;
<br>
<br>
<br>publicSycn1()...{
<br>}
<br>
publicvoidstart()...{
<br>newProducer().start();
<br>newConsumer().start();
<br>}
<br>
publicstaticvoidmain(String[]args)throwsException...{
<br>Sycn1s1=newSycn1();
<br>s1.start();
<br>}
<br>
classProducerextendsThread...{
publicvoidrun()...{
while(true)...{
synchronized(myList)...{
try...{
while(myList.size()==MAX)...{
<br>System.out.println("warning:itsfull!");
<br>myList.wait();
<br>}
<br>Objecto=newObject();
if(myList.add(o))...{
<br>System.out.println("Producer:"+o);
<br>myList.notify();
<br>}
}catch(InterruptedExceptionie)...{
<br>System.out.println("producerisinterrupted!");
<br>}
<br>}
<br>}
<br>}
<br>}
<br>
classConsumerextendsThread...{
publicvoidrun()...{
while(true)...{
synchronized(myList)...{
try...{
while(myList.size()==0)...{
<br>System.out.println("warning:itsempty!");
<br>myList.wait();
<br>}
<br>Objecto=myList.removeLast();
<br>System.out.println("Consumer:"+o);
<br>myList.notify();
}catch(InterruptedExceptionie)...{
<br>System.out.println("consumerisinterrupted!");
<br>}
<br>}
<br>}
<br>}
<br>}
<br>
<br>}2.办法await()/signal()在JDK5.0今后,JAVA供应了新的加倍强健的线程处置机制,包含了同步、锁定、线程池等等,它们能够完成更小粒度上的把持。await()和signal()就是个中用来做同步的两种办法,它们的功效基础上和wait()/notify()不异,完整能够代替它们,可是它们和新引进的锁定机制Lock间接挂钩,具有更年夜的天真性。上面是一个例子代码:
<br>importjava.util.LinkedList;
<br>
<br>importjava.util.concurrent.locks.*;
<br>
publicclassSycn2...{
<br>privateLinkedList<Object>myList=newLinkedList<Object>();
<br>privateintMAX=10;
<br>privatefinalLocklock=newReentrantLock();
<br>privatefinalConditionfull=lock.newCondition();
<br>privatefinalConditionempty=lock.newCondition();
<br>
publicSycn2()...{
<br>}
<br>
publicvoidstart()...{
<br>newProducer().start();
<br>newConsumer().start();
<br>}
<br>
publicstaticvoidmain(String[]args)throwsException...{
<br>Sycn2s2=newSycn2();
<br>s2.start();
<br>}
<br>
classProducerextendsThread...{
publicvoidrun()...{
while(true)...{
<br>lock.lock();
try...{
while(myList.size()==MAX)...{
<br>System.out.println("warning:itsfull!");
<br>full.await();
<br>}
<br>Objecto=newObject();
if(myList.add(o))...{
<br>System.out.println("Producer:"+o);
<br>empty.signal();
<br>}
}catch(InterruptedExceptionie)...{
<br>System.out.println("producerisinterrupted!");
}finally...{
<br>lock.unlock();
<br>}
<br>}
<br>}
<br>}
<br>
classConsumerextendsThread...{
publicvoidrun()...{
while(true)...{
<br>lock.lock();
try...{
while(myList.size()==0)...{
<br>System.out.println("warning:itsempty!");
<br>empty.await();
<br>}
<br>Objecto=myList.removeLast();
<br>System.out.println("Consumer:"+o);
<br>full.signal();
}catch(InterruptedExceptionie)...{
<br>System.out.println("consumerisinterrupted!");
}finally...{
<br>lock.unlock();
<br>}
<br>}
<br>}
<br>}
<br>
<br>}3.堵塞行列办法BlockingQueueBlockingQueue也是JDK5.0的一部分,它是一个已在外部完成了同步的行列,完成体例接纳的是我们的第2种await()/signal()办法。它能够在天生对象时指定容量巨细。它用于堵塞操纵的是put()和take()办法。put()办法相似于我们下面的临盆者线程,容量最年夜时,主动堵塞。take()办法相似于我们下面的消耗者线程,容量为0时,主动堵塞。上面是一个例子代码:
<br>importjava.util.concurrent.*;
<br>
publicclassSycn3...{
<br>privateLinkedBlockingQueue<Object>queue=newLinkedBlockingQueue<Object>(10);
<br>privateintMAX=10;
<br>
publicSycn3()...{
<br>}
<br>
publicvoidstart()...{
<br>newProducer().start();
<br>newConsumer().start();
<br>}
<br>
publicstaticvoidmain(String[]args)throwsException...{
<br>Sycn3s3=newSycn3();
<br>s3.start();
<br>}
<br>
classProducerextendsThread...{
publicvoidrun()...{
while(true)...{
<br>//synchronized(this){
try...{
<br>if(queue.size()==MAX)
<br>System.out.println("warning:itsfull!");
<br>Objecto=newObject();
<br>queue.put(o);
<br>System.out.println("Producer:"+o);
}catch(InterruptedExceptione)...{
<br>System.out.println("producerisinterrupted!");
<br>}
<br>//}
<br>}
<br>}
<br>}
<br>
classConsumerextendsThread...{
publicvoidrun()...{
while(true)...{
<br>//synchronized(this){
try...{
<br>if(queue.size()==0)
<br>System.out.println("warning:itsempty!");
<br>Objecto=queue.take();
<br>System.out.println("Consumer:"+o);
}catch(InterruptedExceptione)...{
<br>System.out.println("producerisinterrupted!");
<br>}
<br>//}
<br>}
<br>}
<br>}
<br>
<br>}你发明这个例子中的成绩了吗?假如没有,我倡议你运转一下这段代码,细心察看它的输入,是否是有上面这个模样的?为何会如许呢?…warning:itsfull!Producer:java.lang.object@4526e2a…你大概会说这是由于put()和System.out.println()之间没有同步酿成的,我也如许以为,我也如许以为,可是你把run()中的synchronized后面的正文往失落,从头编译运转,有变动吗?没有。为何?这是由于,当缓冲区已满,临盆者在put()操纵时,put()外部挪用了await()办法,保持了线程的实行,然后消耗者线程实行,挪用take()办法,take()外部挪用了signal()办法,关照临盆者线程能够实行,以致在消耗者的println()还没运转的情形下临盆者的println()先被实行,以是有了下面的输入。run()中的synchronized实在并没有起甚么感化。关于BlockingQueue人人能够宁神利用,这可不是它的成绩,只是在它和其余对象之间的同步有成绩。关于这类多重嵌套同步的成绩,今后再谈吧,接待人人会商啊!4.管道办法PipedInputStream/PipedOutputStream这个类位于java.io包中,是办理同步成绩的最复杂的举措,一个线程将数据写进管道,另外一个线程从管道读取数据,如许便组成了一种临盆者/消耗者的缓冲区编程形式。上面是一个例子代码,在这个代码我没有利用Object对象,而是复杂的读写字节值,这是由于PipedInputStream/PipedOutputStream不同意传输对象,这是JAVA自己的一个bug,详细的人人能够看sun的注释:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4131126
<br>importjava.io.*;
<br>
publicclassSycn4...{
<br>privatePipedOutputStreampos;
<br>privatePipedInputStreampis;
<br>//privateObjectOutputStreamoos;
<br>//privateObjectInputStreamois;
<br>
publicSycn4()...{
try...{
<br>pos=newPipedOutputStream();
<br>pis=newPipedInputStream(pos);
<br>//oos=newObjectOutputStream(pos);
<br>//ois=newObjectInputStream(pis);
}catch(IOExceptione)...{
<br>System.out.println(e);
<br>}
<br>}
<br>
publicvoidstart()...{
<br>newProducer().start();
<br>newConsumer().start();
<br>}
<br>
publicstaticvoidmain(String[]args)throwsException...{
<br>Sycn4s4=newSycn4();
<br>s4.start();
<br>}
<br>
classProducerextendsThread...{
publicvoidrun()...{
try...{
while(true)...{
<br>intb=(int)(Math.random()*255);
<br>System.out.println("Producer:abyte,thevalueis"+b);
<br>pos.write(b);
<br>pos.flush();
<br>//Objecto=newMyObject();
<br>//oos.writeObject(o);
<br>//oos.flush();
<br>//System.out.println("Producer:"+o);
<br>}
}catch(Exceptione)...{
<br>//System.out.println(e);
<br>e.printStackTrace();
}finally...{
try...{
<br>pos.close();
<br>pis.close();
<br>//oos.close();
<br>//ois.close();
}catch(IOExceptione)...{
<br>System.out.println(e);
<br>}
<br>}
<br>}
<br>}
<br>
classConsumerextendsThread...{
publicvoidrun()...{
try...{
while(true)...{
<br>intb=pis.read();
<br>System.out.println("Consumer:abyte,thevalueis"+String.valueOf(b));
<br>//Objecto=ois.readObject();
<br>//if(o!=null)
<br>//System.out.println("Consumer:"+o);
<br>}
}catch(Exceptione)...{
<br>//System.out.println(e);
<br>e.printStackTrace();
}finally...{
try...{
<br>pos.close();
<br>pis.close();
<br>//oos.close();
<br>//ois.close();
}catch(IOExceptione)...{
<br>System.out.println(e);
<br>}
<br>}
<br>}
<br>}
<br>
<br>//classMyObjectimplementsSerializable{
<br>//}
<br>}
还是要自己一点一点写代码,然后编译,改错再编译好那。还有最重要的是.net网页编程的编译环境非常好,你甚是不需要了解太多工具,对于简单的系统,你可以之了解一些语法就哦了。 http://www.jdon.com/去下载,或到同济技术论坛的服务器ftp://nro.shtdu.edu.cn去下,安装上有什么问题,可以到论坛上去提问。 J2SE开发桌面应用软件比起 VC,VB,DEPHI这些传统开发语言来说,优势好象并不明显。J2ME对于初学者来说,好象又有点深奥,而且一般开发者很难有开发环境。 http://www.jdon.com/去下载,或到同济技术论坛的服务器ftp://nro.shtdu.edu.cn去下,安装上有什么问题,可以到论坛上去提问。 当然你也可以参加一些开源项目,一方面可以提高自己,另一方面也是为中国软件事业做贡献嘛!开发者在互联网上用CVS合作开发,用QQ,MSN,E-mail讨论联系,天南海北的程序员分散在各地却同时开发同一个软件,是不是很有意思呢? 如果要向java web方向发展也要吧看看《Java web从入门到精通》学完再到《Struts2.0入门到精通》这样你差不多就把代码给学完了。有兴趣可以看一些设计模块和框架的包等等。 自从Sun推出Java以来,就力图使之无所不包,所以Java发展到现在,按应用来分主要分为三大块:J2SE,J2ME和J2EE,这也就是Sun ONE(Open Net Environment)体系。J2SE就是Java2的标准版,主要用于桌面应用软件的编程;J2ME主要应用于嵌入是系统开发,如手机和PDA的编程;J2EE是Java2的企业版,主要用于分布式的网络程序的开发,如电子商务网站和ERP系统。 你就该学一学Servlet了。Servlet就是服务器端小程序,他负责生成发送给客户端的HTML文件。JSP在执行时,也是先转换成Servlet再运行的。虽说JSP理论上可以完全取代Servlet,这也是SUN推出JSP的本意,可是Servlet用来控制流程跳转还是挺方便的,也令程序更清晰。接下来你应该学习一下Javabean了,可能你早就看不管JSP在HTML中嵌Java代码的混乱方式了,这种方式跟ASP又有什么区别呢? 吧,现在很流行的Structs就是它的一种实现方式,不过Structs用起来实在是很繁,我们只要学习其精髓即可,我们完全可以设计自己的MVC结构。然后你再研究一下软件Refactoring (重构)和极限XP编程,相信你又会上一个台阶。 做完这些,你不如整理一下你的Java代码,把那些经典的程序和常见的应用整理出来,再精心打造一番,提高其重用性和可扩展性。你再找几个志同道合的朋友成立一个工作室吧
页:
[1]