科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件Java语言深入 多线程程序模型研究

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

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

读者可以编译运行第4个程序,得出的结果和前面的是一样的。但是第4和第3个程序之间最大的差别就是:第4个程序会一直运行下去,不会自动结束。

作者:中国IT实验室 来源:中国IT实验室 2007年8月28日

关键字: 多线程 java

  • 评论
  • 分享微博
  • 分享邮件
   class Scanner implements Runnable{
    String host;    
    int port;
        
    Scanner(String host, int port){
        this.host = host;
        this.port = port;
    }
        
    public void run(){
        Socket s = null;
        try{
            s = new Socket(InetAddress.getByName(host),port);
            System.out.println("The port of " + port + " is opened.");
        }catch(IOException ex){
        }finally{
            try{
                if(s != null) s.close();
            }catch(IOException e){
            }
        }
    }
}
---------------------------------------------------------------------------------------------------------------------
    PortScannerByThreadPool是主程序类,处理输入的4个参数(和第3个程序是一样的):主机名、开始端口、结束端口和线程数。Scanner类定义了真正的”任务“。在PortScannerByThreadPool中通过new ThreadPool(nThreads)创建ThreadPool对象,然后在for循环中通过new Scanner(host,i)创建”任务“对象,再通过tp.execute(ps)把”任务“对象添加到”池“中。

    读者可以编译运行第4个程序,得出的结果和前面的是一样的。但是第4和第3个程序之间最大的差别就是:第4个程序会一直运行下去,不会自动结束。在第3个程序中存在一个isFinished()方法,可以用来判断任务是否处理完毕,而第4个程序中没有这样做。请读者自己思考这个问题。

    在第3和第4个程序中,我们可以概括出多线程的模型。第3个程序的线程”池“里装的要处理的对象,第4个程序的线程”池“里装的是”工人“,还需要通过定义”任务“并给把它”派工“给”工人“。我个人比较偏好后者的线程池模型,虽然类的个数多了几个,但逻辑很清晰。不管怎样,第3和第4个程序中关键的部分都大同小异,就是2个synchronized程序块中的内容,如下(第4个程序中的):
synchronized(queue) {
    queue.addLast(r);
    queue.notifyAll();
}

synchronized(queue) {
    while (queue.isEmpty()) {
        try{
            queue.wait();
        }catch (InterruptedException ignored){
        }
    }

    r = (Runnable) queue.removeFirst();
}

    一般拿synchronized用来定义方法或程序块,这样可以在多线程同时访问的情况下,保证在一个时刻只能有一个线程对这部分内容进行访问,避免了数据出错。在第3个程序中通过List entries = Collections.synchronizedList(new LinkedList())来定义”池“,在第4个程序中直接用LinkedList queue,都差不多,只是Collections.synchronizedList()可以保证”池“的同步,其实”池“里的内容访问都是在synchronized定义的程序块中,所以不用Collections.synchronizedList()也是可以的。

    wait()和notifyAll()是很重要的,而且这2个方法是Object基类的方法,所以任何一个类都是可以使用的。这里说明一个可能产生混淆的问题:queue.wait()并不是说queue对象需要进行等待,而是说queue.wait()所在的线程需要进行等待,并且释放对queue的锁,把对queue的访问权交给别的线程。如果读者对这2个方法难以理解,建议参考JDK的文档说明。

    好了,通过以上4个例子的理解,读者应该能对多线程的程序设计有了一定的理解。第3和第4个程序对应线程模型是非常重要的,可以说是多线程程序设计过程中不可或缺的内容。

    如果读者对以上的内容有任何疑问,可以和我联系,qianh@cntmi.com 版权所有,严禁转载

参考资料:
1、《Java Networking Programming, 3rd》written by Elliotte Rusty Harold, Published by O'Reilly,2004  
2、“Thread pools and work queues” written by Brian Goetz, Principal Consultant, Quiotix Corp. 查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章