您的位置: 旅游网 > 时尚

Java语言深入 多线程程序模型研究(2)

发布时间:2019-09-13 19:18:21

以上程序在for循环结构中创建PortProcessor对象,PortProcessor类是线程类,其关键的Socket在publicvoidrun()方法中实现。此程序比第一个单线程的程序运行效率提高很多倍,几乎在几秒钟内得出结果。所以可见多线程处理是何等的重要。

程序(javaPortScannerMultiThread10.1.1.10011000)运行结果如下:

Theport25isopenedat10.1.1.100

Theport42isopenedat10.1.1.100

Theport88isopenedat10.1.1.100

...

仔细对第2个程序分析,不难发现其中的问题:创建的线程个数是不固定的,取决于输入的第二和第三个参数。如果扫描1~100端口,那么主线程就产生100个线程来分别处理;如果扫描1~10000端口,主线程就会产生10000个线程来进行处理。在JVM中创建如此多的线程同样会带来性能上的问题,因为线程的创建和消失都是需要花费系统资源的。所以以上的第二个程序也存在明显的不足。

所以,我们需要一个确定数量的线程在JVM中运行,这样就需要了解“线程池”(ThreadPool)的概念。线程池在多线程程序设计中是比不可少的,而且初学者不太容易掌握,下面通过对线程池的介绍,结合第3和第4个程序,引出两种常用的线程池模型。

第一种实现线程池的方法是:创建一个”池“,在”池“中增加要处理的数据对象,然后创建一定数量的线程,这些线程对”池“中的对象进行处理。当”池“是空的时候,每个线程处于等待状态;当往”池“里添加一个对象,通知所有等待的线程来处理(当然一个对象只能有一个线程来处理)。

第二种方法是:同样创建一个”池“,但是在”池“中放的不是数据对象,而是线程,可以把”池“中的一个个线程比喻成一个个”工人“,当没有任务的时候,”工人“们严阵以待;当给”池“添加一个任务后,”工人“就开始处理并直到处理完成。

在第3个程序中,定义了List类型的entries作为“池”,这个“池”用来保存需要扫描的端口,List中的元素必须是Object类型,不能用基本数据类型int往池里添加,而需要用使用Integer。在processMethod()方法中,首先就启动一定数量的PortThread线程,同时在while循环中通过entries.add(0,newInteger(port))往“池”里添加对象。在PortThread类的run()方法中通过entry=(Integer)entries.remove(entries.size()-1);取得“池”中的对象,转换成int后传递给Socket构造方法。

第3个程序如下:

-----------------------------------------------------------------------------------------------------------------------

importjava.io.IOException;

importjava.net.InetAddress;

importjava.net.Socket;

importjava.net.UnknownHostException;

importjava.util.Collections;

importjava.util.LinkedList;

importjava.util.List;

publicclassPortScanner{

privateListentries=Collections.synchronizedList(newLinkedList());//这个”池“比较特别

intnumofthreads;

staticintport;

intbeginport;

intendport;

InetAddressremote=null;

publicbooleanisFinished(){

if(port>=endport){

returntrue;

}else{

returnfalse;

}

}

PortScanner(InetAddressaddr,intbeginport,intendport,intnumofthreads){

this.remote=addr;

this.beginport=beginport;

this.endport=endport;

this.numofthreads=numofthreads;

}

publicvoidprocessMethod(){

for(inti=0;i<numofthreads;i++){//创建一定数量的线程并运行

Threadt=newPortThread(remote,entries,this);

t.start();

}

port=beginport;

while(true){

if(entries.size()>numofthreads){

try{

Thread.sleep(1000);//”池“中的内容太多的话就sleep

}catch(InterruptedExceptionex){

}

continue;

}

synchronized(entries){

if(port>endport)break;

entries.add(0,newInteger(port));//往”池“里添加对象,需要使用int对应的Integer类

entries.notifyAll();

port++;

}

}

}

publicstaticvoidmain(String[]args){

Stringhost=null;

intbeginport=1;

intendport=65535;

intnThreads=100;

try{

host=args[0];

beginport=Integer.parseInt(args[1]);

endport=Integer.parseInt(args[2]);

nThreads=Integer.parseInt(args[3]);

if(beginport<=0||endport>=65536||beginport>endport){

thrownewException("Portisillegal");

}

}catch(Exceptione){

System.out.println("Usage:javaPortScannerSingleThreadhostbeginportendportnThreads");

System.exit(0);

}

try{

PortScannerscanner=newPortScanner(InetAddress.getByName(host),beginport,endport,nThreads);

scanner.processMethod();

}catch(UnknownHostExceptionex){

}

}

}

classPortThreadextendsThread{

privateInetAddressremote;

privateListentries;

PortScannerscanner;

PortThread(InetAddressadd,Listentries,PortScannerscanner){

this.remote=add;

this.entries=entries;

this.scanner=scanner;

}

publicvoidrun(){

Integerentry;

while(true){

synchronized(entries){

while(entries.size()==0){

if(scanner.isFinished())return;

try{

entries.wait();//”池“里没内容就只能等了

}catch(InterruptedExceptionex){

}

}

entry=(Integer)entries.remove(entries.size()-1);//把”池“里的东西拿出来进行处理

}

Sockets=null;

try{

s=newSocket(remote,entry.intValue());

System.out.println("Theportof"+entry.toString()+"oftheremote"+remote+"isopened.");

}catch(IOExceptione){

}finally{

try{

if(s!=null)s.close();

}catch(IOExceptione){

}

}

}

}

}

查看本文来源

小孩白天咳嗽晚上不咳嗽怎么回事
小孩口臭怎么办
婴儿手心出汗是怎么回事
小孩不消化口臭怎么办
猜你会喜欢的
猜你会喜欢的