免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 4205 | 回复: 29
打印 上一主题 下一主题

大家帮我看看这段代码! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-06-01 08:37 |只看该作者 |倒序浏览
在www.ibm.com上面搜索到的关于java sockets 编程的文章,文章题目叫做java sockets 101 tutorial。
we文章详细介绍了java sockets 编程。
文章下载的地址:http://www-128.ibm.com/developerworks/edu/j-dw-javasocks-i.html

俺看了文章后,觉得茅舍顿开啊。
可是对于最后一种pooled socket ,还是越看越糊涂。里面说这种pooled socket比前面的multithread socket的好处是效率更高,而且可以限制服务器能同时处理的客户端连接的个数。
服务器端的代码如下:(功能是:根据客户端上送的文件名,把服务器端对应于该文件名的文件传给客户端,有点类似于ftp)。


  1. import java.io.*;
  2. import java.net.*;
  3. import java.util.*;
  4. public class PooledRemoteFileServer {
  5. protected int maxConnections;
  6. protected int listenPort;
  7. protected ServerSocket serverSocket;
  8. public PooledRemoteFileServer(int aListenPort, int maxConnections) {
  9. listenPort = aListenPort;
  10. this.maxConnections = maxConnections;
  11. }
  12. public void acceptConnections() {
  13. try {
  14. ServerSocket server = new ServerSocket(listenPort, 5);
  15. Socket incomingConnection = null;
  16. while (true) {
  17. incomingConnection = server.accept();
  18. handleConnection(incomingConnection);
  19. }
  20. } catch (BindException e) {
  21. System.out.println("Unable to bind to port " + listenPort);
  22. } catch (IOException e) {
  23. System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort);
  24. }
  25. }
  26. protected void handleConnection(Socket connectionToHandle) {
  27. PooledConnectionHandler.processRequest(connectionToHandle);
  28. }
  29. public static void main(String[] args) {
  30. PooledRemoteFileServer server = new PooledRemoteFileServer(3000, 3);
  31. server.setUpHandlers();
  32. server.acceptConnections();
  33. }
  34. public void setUpHandlers() {
  35. for (int i = 0; i < maxConnections; i++) {
  36. PooledConnectionHandler currentHandler = new PooledConnectionHandler();
  37. new Thread(currentHandler, "Handler " + i).start();
  38. }
  39. }
  40. }

复制代码


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


  1. import java.io.*;
  2. import java.net.*;
  3. import java.util.*;
  4. public class PooledConnectionHandler implements Runnable {
  5. protected Socket connection;
  6. protected static List pool = new LinkedList();
  7. public PooledConnectionHandler() {
  8. }
  9. public void handleConnection() {
  10. try {
  11. Presented by developerWorks, your source for great tutorials ibm.com/developerWorks

  12. PrintWriter streamWriter = new PrintWriter(connection.getOutputStream());
  13. BufferedReader streamReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
  14. String fileToRead = streamReader.readLine();
  15. BufferedReader fileReader = new BufferedReader(new FileReader(fileToRead));
  16. String line = null;
  17. while ((line = fileReader.readLine()) != null)
  18. streamWriter.println(line);
  19. fileReader.close();
  20. streamWriter.close();
  21. streamReader.close();
  22. } catch (FileNotFoundException e) {
  23. System.out.println("Could not find requested file on the server.");
  24. } catch (IOException e) {
  25. System.out.println("Error handling a client: " + e);
  26. }
  27. }
  28. public static void processRequest(Socket requestToHandle) {
  29. synchronized (pool) {
  30. pool.add(pool.size(), requestToHandle);
  31. pool.notifyAll();
  32. }
  33. }
  34. public void run() {
  35. while (true) {
  36. synchronized (pool) {
  37. while (pool.isEmpty()) {
  38. try {
  39. pool.wait();
  40. } catch (InterruptedException e) {
  41. return;
  42. }
  43. }
  44. connection = (Socket) pool.remove(0);
  45. }
  46. handleConnection();
  47. }
  48. }
  49. }
复制代码



大家看到这段代码就是通过class PooledRemoteFileServer 类里面通过setUpHandlers() 方法创建并启动三个线程,就是想让服务器能够同时处理3个连接。
可是我怎么感觉“同时处理3个连接”目的达不到,因为这三个线程在对象pool上进行同步处理了,就是class PooledConnectionHandler 里面的 processRequest方法采用了synchronized (pool) ,而且run的方面里面也采用了synchronized (pool) ,这样其实就是三个线程在竞争pool。

既然这些线程是在竞争pool,那么在某个时刻也只能有一个线程占用了这个pool,而其他线程因占用不到这个pool所以阻塞在某个地方,既然是这样,那怎么能够实现“同时处理3个客户连接”的目的???

因为是ibm.com上的文章,所以可能是我理解错了,而ibm一般不会错的。

请大侠们帮看看啊。

论坛徽章:
0
2 [报告]
发表于 2006-06-01 08:47 |只看该作者
http://www-128.ibm.com/developerworks/edu/j-dw-javasocks-i.html
请问:这个网址,要看到你所看到的内容要注册吗?

论坛徽章:
0
3 [报告]
发表于 2006-06-01 08:51 |只看该作者

回复 2楼 xxjoyjn 的帖子

要注册,用你的E-mail注册,再用至少八个字符的秘密,很快的。

论坛徽章:
0
4 [报告]
发表于 2006-06-01 11:38 |只看该作者

java初学者问个线程问题!

构造一个线程体,其他代码省略,只列出run()的代码:


  1. public void run() {
  2.   while (true) {
  3.       synchronized (pool) {
  4.       while (pool.isEmpty()) {
  5.             try {
  6.               pool.wait();
  7.            } catch (InterruptedException e) {
  8.               return;
  9.            }
  10.       } //while(pool.isEmpty) end

  11.         connection = (Socket) pool.remove(0);

  12.      } //sync end

  13.      handleConnection();
  14.    
  15.   } //while true end

  16. }//run end

复制代码



pool是一个LindedList实例;
主程序创建了多个这样的线程。
程序就是在几个线程同时竞争pool的时候,如果pool不空的时候,假设某个线程A取得了pool的控制权,然后调用handleConnection()处理客户端连接。

请教:请问线程A什么时候释放对pool的控制权?是不是程序执行到synchronized (pool) {}块外面的代码
handleConnection()时候就释放了对pool的lock,还是说要等到handleConnection()执行完毕后,继续执行while(true)下一循环,如果碰到pool.isEmpty==true的时候调用 pool.wait来释放Lock?

论坛徽章:
0
5 [报告]
发表于 2006-06-01 13:53 |只看该作者
这个问题问得好,见如下代码:
synchronized (pool) {
      while (pool.isEmpty()) {
            try {
              pool.wait();
           } catch (InterruptedException e) {
              return;
           }
      } //while(pool.isEmpty) end

        connection = (Socket) pool.remove(0);

     } //sync end

你先用synchronized把pool锁定,然后pool.wait(),这样,谁都没办法唤醒pool了,就好比把钥匙锁在屋里,然后怎么开门呢?典型的死锁

--这个说法不完全正确,synchronized 不阻止别的线程运行pool.notify() 和 pool.notifyAll();主要是确保pool.remove(0);的时候没有别人访问而引起数据不一致。

[ 本帖最后由 perryhg 于 2006-6-1 15:48 编辑 ]

论坛徽章:
0
6 [报告]
发表于 2006-06-01 15:37 |只看该作者
关键在这里:
      try {
              pool.wait();
           } catch (InterruptedException e) {
              return;
           }
--- 此处解释有误 --
当有线程执行了pool.notifyAll()的时候,就造成了InterruptedException,这段代码就return了,就离开synchronized段了,于是就自动解锁了。
---------------------

补充如下:
pool.wait()以后,只有两种情况会发生,一种是notify以后,以正常方式继续执行代码,另一种就是整个线程被interrupt,造成Exception以后直接返回,结束线程。这里显然是notify的,不是interrupted的,前面解释错误,从而造成楼主困扰,抱歉
---------------------

[ 本帖最后由 perryhg 于 2006-6-3 17:07 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2006-06-01 17:29 |只看该作者

回复 6楼 perryhg 的帖子

既然这个线程的run() return了,那是不是这个线程就退出了??意思是这个线程是不是死掉了??那pool里面可以用的线程不就少了一个了??
另外,我感觉这个例子并不能同时处理多个客户端连接(例子里面是3个),因为比如说线程A正在处理某一个连接的过程中,A应当还是占有pool的锁的,假设这个时候又来了一个客户端连接,程序就会执行processRequest()了,可是这个时候processRequest()并没有占有pool的锁,所以processRequest()就一直阻塞到获得这个锁,既然是这样,新到的客户端连接并不能得到处理了,何以象文章说的能同时处理多个客户端连接??

郁闷啊................

论坛徽章:
0
8 [报告]
发表于 2006-06-01 18:26 |只看该作者
还是运行一下就知道了,这里就体现log4j的power了,因为可以显示出是哪个线程输出的
2006-06-01 18:24:22,764 [Handler 0] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - waken
2006-06-01 18:24:22,764 [Handler 0] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - socket aquired
2006-06-01 18:24:22,764 [Handler 1] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - waken
2006-06-01 18:24:22,764 [Handler 2] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - waken
以上为第一个socket连接

2006-06-01 18:24:26,842 [Handler 1] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - waken
2006-06-01 18:24:26,842 [Handler 1] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - socket aquired
2006-06-01 18:24:26,842 [Handler 2] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - waken
以上为第二个socket连接

2006-06-01 18:24:34,670 [Handler 2] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - waken
2006-06-01 18:24:34,670 [Handler 2] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - socket aquired
以上为第三个socket连接

然后是第四个socket连接,但是因为没有空余的线程来处理,所以连接上以后没有log
在第四个窗口中开始输入,并无任何反应

在第一个窗口中输入,输入完以后,第一个和第四个窗口同时产生输出,因为第一个窗口输出完后,释放了Handler 0,然后Handler 0就接下来处理了第四个窗口的请求,并完成了输出。
2006-06-01 18:24:59,810 [Handler 0] DEBUG org.v66.testlog.PooledConnectionHandler  - run() - socket aquired

[ 本帖最后由 perryhg 于 2006-6-1 18:32 编辑 ]

论坛徽章:
0
9 [报告]
发表于 2006-06-02 09:01 |只看该作者

回复 8楼 perryhg 的帖子

结果肯定是正确的,因为是IBM写的哟。
可是我还是不理解为什么。
比如线程A正在处理某一个客户端请求,这个时候线程A应当占用这个pool的,这样导致主线程(处理processreques)和其他两个子线程B、C因占用不到这个pool而导致阻塞,直到线程A干完了所有的事情后释放了pool后,其他线程才能继续运行吧。
这样不就成了“同时只能处理一个客户端请求了”。
何以能同时处理多个(例子里是3个)客户端请求??

搞不清楚这是为什么。

论坛徽章:
0
10 [报告]
发表于 2006-06-02 09:46 |只看该作者
你看一下Java Doc就知道了,pool.wait()的时候释放锁,但被notify的时候自动获得
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP