2007-04-24

java 细枝末节

2. 关于Thread的误解

这个误解相当常见。
我们说一个方法是否是线程安全的,判断的标准只有一个,
这个方法是否访问了 可以写的“成员变量”。(所谓的state)
注意,只有两个条件:
(1)可以改变的 (2)成员变量
如果访问了可以写的“成员变量”,那么这个方法不是 线程安全的。
如果没有访问 可以写的“成员变量”,那么这个方法是 线程安全的。

方法的线程安全特性和传进来的参数毫无关系。
举个例子说明,为什么和参数毫无关系。

代码
  1. public class A {  
  2.    // 这个方法没有访问任何成员变量,本身是线程安全的。  
  3.    public void changeBuf(StringBuffer buf){  
  4.       buf.append("aaa");  
  5.    }  
  6. };  
  7.   
  8. 公用变量  
  9. public class Common{  
  10.    public static StringBuffer buf = new StringBuffer();  
  11. }  
  12.   
  13. Thread 1的代码:  
  14. A a1 = new A();  
  15. a1.changeBuf(Common.buf);  
  16.   
  17. Thread 2的代码:  
  18. A a2 = new A();  
  19. a2.changeBuf(Common.buf);  

我们看到,这个Common.buf还是存在共享冲突。
但这个不是A.changeBuf()方法的问题,而是调用这个方法的问题。
而且,我们看到,这里的线程安全和是否共享实例根本就没有关系。
你就是创建1000个线程,分别调用1000个不同的实例,这种调用方法还是线程不安全。
结果和这1000个线程,都调用同一个共享实例的结果,没有任何区别。

这就是说,只要你不在Action类里面声明可写的成员变量,那么多个Request使用一个共享Action,还是分别使用不同的Action,结果完全一样。
(这种情况基本没有,因为Servlet,Action就是Stateless的,没有理由声明 可写的成员变量)

类和Object实例的基本概念:
同一个类的每个Object Instance都有自己的"成员变量备份",但是所有的Object Instance都共享同一份Java代码,不管这个方法是static method还是instance method.

线程的基本概念:
每个线程有自己的运行栈。线程只在自己的运行栈上运行方法。线程只和类的方法(method)有关。线程并不和任何具体Object实例有直接关系。

由于这个问题涉及的概念比较复杂,如果有疑问,
我可以举更多详细的例子,一步一步地说明所有问题。
因为这个误解太普遍了。不解决这个误解,很多问题的讨论都是南辕北辙,根本不成立的。

(3)关于Request的误解。
我想,这个Request应该是说HttpRequest这个参数。
我想要说明的是,根据基本常识,这个HttpRequest这个参数绝不可能被共享。

我查阅了好久Tomcat的源代码,但没有找到相关的从Socket连接生成Request的代码。所以,不能提供有力的证据。只能根据常识下这个判断。

希望有了解Tomcat源代码的高手,能够指教。

评论
发表评论

您还没有登录,请登录后发表评论

jianfeng008cn
搜索本博客
我的相册
11f2e450-fb73-39c2-8124-8f1fda304b90-thumb
旋转 SNV10095
共 1 张
存档
最新评论