友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
一世书城 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

Java编程思想第4版[中文版](PDF格式)-第172章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




除此以外,运用线程时还要注意一个非常特殊的问题。由于根据Java 的设计,它允许我们根据需要创建任意 

数量的线程——至少理论上如此(例如,假设为一项工程方面的有限元素分析创建数以百万的线程,这对 

Java 来说并非实际)。然而,我们一般都要控制自己创建的线程数量的上限。因为在某些情况下,大量线程 

会将场面变得一团糟,所以工作都会几乎陷于停顿。临界点并不象对象那样可以达到几千个,而是在 100 以 

下。一般情况下,我们只创建少数几个关键线程,用它们解决某个特定的问题。这时数量的限制问题不大。 

但在较常规的一些设计中,这一限制确实会使我们感到束手束脚。  

大家要注意线程处理中一个不是十分直观的问题。由于采用了线程“调度”机制,所以通过在run()的主循 

环中插入对 sleep()的调用,一般都可以使自己的程序运行得更快一些。这使它对编程技巧的要求非常高, 

特别是在更长的延迟似乎反而能提高性能的时候。当然,之所以会出现这种情况,是由于在正在运行的线程 

准备进入“休眠”状态之前,较短的延迟可能造成“sleep()结束”调度机制的中断。这便强迫调度机制将其 

中止,并于稍后重新启动,以便它能做完自己的事情,再进入休眠状态。必须多想一想,才能意识到事情真 

正的麻烦程度。  

本章遗漏的一件事情是一个动画例子,这是目前程序片最流行的一种应用。然而,Java JDK 配套提供了解决 

这个问题的一整套方案(并可播放声音),大家可到java。sun。 的演示区域下载。此外,我们完全有理由 

相信未来版本的Java 会提供更好的动画支持——尽管目前的 Web 涌现出了与传统方式完全不同的非 Java、 

非程序化的许多动画方案。如果想系统学习Java 动画的工作原理,可参考《Core Java——核心Java 》一 

书,由Corn ell&Horstmann 编著,Prentice …Hall 于 1997 年出版。若欲更深入地了解线程处理,请参考 

 《Concurrent Programming in Java——Java 中的并发编程》,由Doug Lea 编著,Addison…Wiseley 于 

1997 年出版;或者《Java Threads——Java 线程》,Oaks&Wong 编著,O'Reilly 于 1997 年出版。  



14。7 练习  



(1) 从Thread 继承一个类,并(过载)覆盖 run()方法。在run()内,打印出一条消息,然后调用 

sleep()。重复三遍这些操作,然后从run()返回。在构建器中放置一条启动消息,并覆盖 finalize(),打印 

一条关闭消息。创建一个独立的线程类,使它在run()内调用System。gc()和 System。runFinalization(), 

并打印一条消息,表明调用成功。创建这两种类型的几个线程,然后运行它们,看看会发生什么。  

(2) 修改Counter2。java ,使线程成为一个内部类,而且不需要明确保存指向Counter2 的一个。  

(3) 修改Sharing2。java,在TwoCounter 的run()方法内部添加一个synchronized (同步)块,而不是同步 

整个run()方法。  



                                                               535 


…………………………………………………………Page 537……………………………………………………………

(4) 创建两个Thread 子类,第一个的run()方法用于最开始的启动,并捕获第二个Thread 对象的句柄,然 

后调用wait()。第二个类的run()应在过几秒后为第一个线程调用modifyAll(),使第一个线程能打印出一 

条消息。  

(5) 在Ticker2 内的Counter5。java 中,删除yield(),并解释一下结果。用一个sleep()换掉yield(),再 

解释一下结果。  

(6) 在ThreadGroup1。java 中,将对sys。suspend()的调用换成对线程组的一个wait()调用,令其等候2 秒 

钟。为了保证获得正确的结果,必须在一个同步块内取得 sys 的对象锁。  

(7) 修改Daemons。java,使main()有一个 sleep(),而不是一个readLine()。实验不同的睡眠时间,看看会 

有什么发生。  

(8) 到第7 章(中间部分)找到那个GreenhouseControls。java 例子,它应该由三个文件构成。在 

Event。java 中,Event 类建立在对时间的监视基础上。修改这个 Event,使其成为一个线程。然后修改其余 

的设计,使它们能与新的、以线程为基础的Event 正常协作。  



                                                                       536 


…………………………………………………………Page 538……………………………………………………………

                           第 15 章  网络编程  



  

历史上的网络编程都倾向于困难、复杂,而且极易出错。  

程序员必须掌握与网络有关的大量细节,有时甚至要对硬件有深刻的认识。一般地,我们需要理解连网协议 

中不同的“层”(Layer)。而且对于每个连网库,一般都包含了数量众多的函数,分别涉及信息块的连接、 

打包和拆包;这些块的来回运输;以及握手等等。这是一项令人痛苦的工作。  

但是,连网本身的概念并不是很难。我们想获得位于其他地方某台机器上的信息,并把它们移到这儿;或者 

相反。这与读写文件非常相似,只是文件存在于远程机器上,而且远程机器有权决定如何处理我们请求或者 

发送的数据。  

Java 最出色的一个地方就是它的“无痛苦连网”概念。有关连网的基层细节已被尽可能地提取出去,并隐藏 

在JVM 以及Java 的本机安装系统里进行控制。我们使用的编程模型是一个文件的模型;事实上,网络连接 

 (一个“套接字”)已被封装到系统对象里,所以可象对其他数据流那样采用同样的方法调用。除此以外, 

在我们处理另一个连网问题——同时控制多个网络连接——的时候,Java 内建的多线程机制也是十分方便 

的。  

本章将用一系列易懂的例子解释Java 的连网支持。  



15。1 机器的标识  



当然,为了分辨来自别处的一台机器,以及为了保证自己连接的是希望的那台机器,必须有一种机制能独一 

无二地标识出网络内的每台机器。早期网络只解决了如何在本地网络环境中为机器提供唯一的名字。但 Java 

面向的是整个因特网,这要求用一种机制对来自世界各地的机器进行标识。为达到这个目的,我们采用了 IP 

 (互联网地址)的概念。IP 以两种形式存在着:  

(1) 大家最熟悉的DNS (域名服务)形式。我自己的域名是bruceeckel。。所以假定我在自己的域内有一 

台名为Opus 的计算机,它的域名就可以是 Opus。bruceeckel。。这正是大家向其他人发送电子函件时采用 

的名字,而且通常集成到一个万维网(WWW)地址里。  

(2) 此外,亦可采用“四点”格式,亦即由点号(。)分隔的四组数字,比如202。98。32。111 。  

不管哪种情况,IP地址在内部都表达成一个由32 个二进制位(bit)构成的数字(注释①),所以IP地址 

的每一组数字都不能超过255。利用由java 提供的 static InetAddress。getByName(),我们可以让一个 

特定的 Java 对象表达上述任何一种形式的数字。结果是类型为InetAddress 的一个对象,可用它构成一个 

 “套接字”(Socket),大家在后面会见到这一点。  

  

①:这意味着最多只能得到40 亿左右的数字组合,全世界的人很快就会把它用光。但根据目前正在研究的新 

IP编址方案,它将采用 128 bit 的数字,这样得到的唯一性IP地址也许在几百年的时间里都不会用完。  

  

作为运用 InetAddress。getByName()一个简单的例子,请考虑假设自己有一家拨号连接因特网服务提供者 

 (ISP),那么会发生什么情况。每次拨号连接的时候,都会分配得到一个临时 IP地址。但在连接期间,那 

个 IP 地址拥有与因特网上其他 IP 地址一样的有效性。如果有人按照你的 IP地址连接你的机器,他们就有可 

能使用在你机器上运行的Web 或者 FTP 服务器程序。当然这有个前提,对方必须准确地知道你目前分配到的 

IP。由于每次拨号连接获得的IP 都是随机的,怎样才能准确地掌握你的IP 呢?  

下面这个程序利用 InetAddress。getByName()来产生你的 IP 地址。为了让它运行起来,事先必须知道计算机 

的名字。该程序只在Windows 95 中进行了测试,但大家可以依次进入自己的 “开始”、“设置”、“控制面 

板”、“网络”,然后进入“标识”卡片。其中,“计算机名称”就是应在命令行输入的内容。  

  

//: WhoAmI。java  

// Finds out your network address when you're   

// connected to the Internet。  

package c15;  

import java。*;  

  

public class WhoAmI {  

  public static void main(String'' args)   



                                                                        537 


…………………………………………………………Page 539……………………………………………………………

      throws Exception {  

    if(args。length != 1) {  

      System。err。println(  

        〃Usage: WhoAmI MachineName〃);  

      System。exit(1);  

    }  

    InetAddress a =   

      InetAddress。getByName(args'0');  

    System。out。println(a);  

  }  

} ///:~  

  

就我自己的情况来说,机器的名字叫作“Colossus”(来自同名电影,“巨人”的意思。我在这台机器上有 

一个很大的硬盘)。所以一旦连通我的ISP,就象下面这样执行程序:  

java whoAmI Colossus  

得到的结果象下面这个样子(当然,这个地址可能每次都是不同的):  

Colossus/202。98。41。151  

假如我把这个地址告诉一位朋友,他就可以立即登录到我的个人Web 服务器,只需指定目标地址 

http://202。98。41。151 即可(当然,我此时不能断线)。有些时候,这是向其他人发送信息或者在自己的 

Web 站点正式出台以前进行测试的一种方便手段。  



15。1。1 服务器和客户机  



网络最基本的精神就是让两台机器连接到一起,并相互“交谈”或者“沟通”。一旦两台机器都发现了对 

方,就可以展开一次令人愉快的双向对话。但它们怎样才能“发现”对方呢?这就象在游乐园里那样:一台 

机器不得不停留在一个地方,侦听其他机器说:“嘿,你在哪里呢?”  

 “停留在一个地方”的机器叫作“服务器”(Server);到处“找人”的机器则叫作“客户机”(Client) 

或者“客户”。它们之间的区别只有在客户机试图同服务器连接的时候才显得非常明
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!