Java 多线程问题

2015-04-28 00:02:10 +08:00
 HelloWorld11

各位,晚上好!最近在学 Java Servlet,遇到一个问题,请大家帮忙看看:

我们都知道,一般情况下,Servlet是单实例 多线程的。

假设现在有一个实例,A、B两个用户同时用到了这个实例,假设A、B同时访问 service()方法。那么应该是有2个线程。 我的问题是,因为 service()方法的入口(跟C++函数的入口应该一样吧)只有一个,A、B同时(就是同时,不是同时段哈~)调用service()方法的话,不会冲突吗?

对了,现在服务器都是多核,支持多线程的,A、B两个线程恰好同时刻运行应该是可以的吧。 现在不管有没有什么共享变量,线程安全的问题。 我就是想知道,2个线程同时访问一个方法,会发生什么???或者,在JVM的调度中,是不是根本不会让这两个线程同时运行,即使服务器支持多线程。

请大家帮忙,让小白理解哈~~~

4176 次点击
所在节点    Java
30 条回复
wickila
2015-04-28 00:08:22 +08:00
两个线程访问同时调用一个方法会造成你方法里面的那些变量值都不是你预期的那样,可能A线程在执行的时候里面某个变量被B线程给改变了,所以一般都需要加线程锁
ryd994
2015-04-28 00:59:29 +08:00
这叫可重入性,reentrancy
似乎Java对此有专门的锁
ryd994
2015-04-28 01:04:18 +08:00
我又查了一下,Java所有的方法都是可重入的
重入锁是为了防止重入的时候自己把自己死锁而设置的。
ryd994
2015-04-28 01:04:47 +08:00
@wickila Java作为动态语言还怕重入?
phx13ye
2015-04-28 01:07:48 +08:00
都进自己线程栈顶并执行
miaoever
2015-04-28 01:14:31 +08:00
线程会有自己的stack,所以各自执行 service 没有任何问题。当然读写共享变量就会产生各种 race condition 的问题。
qiyi
2015-04-28 01:42:36 +08:00
摘自jvm规范(2.6)
A frame is used to store data and partial results, as well as to perform dynamiclinking, return values for methods, and dispatch exceptions.A new frame is created each time a method is invoked. A frame is destroyed whenits method invocation completes, whether that completion is normal or abrupt (itthrows an uncaught exception). Frames are allocated from the Java Virtual Machinestack (§2.5.2) of the thread creating the frame. Each frame has its own array oflocal variables (§2.6.1), its own operand stack (§2.6.2), and a reference to the run-time constant pool (§2.5.5) of the class of the current method.
A frame may be extended with additional implementation-specific information, such asdebugging information.The sizes of the local variable array and the operand stack are determined atcompile-time and are supplied along with the code for the method associated withthe frame (§4.7.3). Thus the size of the frame data structure depends only on theimplementation of the Java Virtual Machine, and the memory for these structurescan be allocated simultaneously on method invocation
helloworld00
2015-04-28 04:02:22 +08:00
lz 我们是同一个class new出来的object吗?
Andiry
2015-04-28 04:11:53 +08:00
同步保护的不是方法,而是数据
zts1993
2015-04-28 07:36:35 +08:00
用局部变量不就没有问题了。加群并不是一个好方案
kifile
2015-04-28 07:43:41 +08:00
对于局部变量没有影响,只不过对于成员变量就可能导致发生值改变,得到的数据与预期不符,应该要加锁
flaty
2015-04-28 08:38:15 +08:00
为什么说到重入了..~~
多线程,单实例,每个线程的执行栈(或叫执行体)都是不一样的,方法本就是在线程的执行栈的啊,
同 @phx13ye @miaoever
xinyewdz
2015-04-28 08:42:37 +08:00
所有方法都存放在方法区,像模板一样。线程调用的时候,这个方法会在线程自己的栈内存执行。
comicfans44
2015-04-28 09:03:50 +08:00
每个线程都有自己的堆栈(可以理解为局部变量的所在区域),因此一个方法在多个线程上执行的时候,局部变量(也包括HttpServletResponse HttpServletRequest这些由container传递给你的变量)都是特定于线程的,不存在任何冲突的问题。当然也不会有什么"JVM不会让两个线程同时运行"的说法。

对于servlet来说,只要你不在service方法(或者service间接调用的doPost doGet或任意你自定义的方法)中访问共享的变量(比如servlet的成员变量或者静态成员变量,由于servlet是单实例的),那就完全不需要考虑这个问题。

servlet的init和destory两个可供重载的方法,由container一次调用,如果有共享的成员变量的初始化和销毁操作,可考虑在这两处操作。

举例:
Servlet每被访问一次就打印一行Hello World,多个线程无需访问共享的servlet成员变量,无需考虑同步。
Servlet记录自己一共被访问多少次,需要一个成员变量记录,则更新此变量时需要考虑同步(可能在多线程中被访问更新)
khan
2015-04-28 09:18:27 +08:00
线程`独立栈` `共享堆`. 如果在没有上层作用域外部变量的情况下, 俩线程同时调用某个方法貌似不会发生什么. 如果有上层作用域外部变量, 那就是常规的抢占资源问题了. 外部变量的写行为不可预估.
khan
2015-04-28 09:19:27 +08:00
@ryd994 跟动态语言没啥关系, 你即使用 c 也是这德性
HelloWorld11
2015-04-28 09:35:31 +08:00
@helloworld00 应该是吧~~~,这名字也是巧了~ 呼叫 Helloworld,,,
anexplore
2015-04-28 09:42:21 +08:00
说java是动态语言的我也是醉了。。。
HelloWorld11
2015-04-28 09:56:49 +08:00
@flaty 就是说虽然是同一个方法,但是线程调用的时候,是拷贝到自己的线程栈执行的么?
iyangyuan
2015-04-28 09:58:25 +08:00
java有个名词叫虚拟机栈,是线程私有的,栈上用来放方法帧,方法帧中又包含了局部变量表,所以,如果写操作只针对局部变量,这样是没有任何问题的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/186844

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX