Java 多线程资源共享的问题

2019-04-11 14:44:44 +08:00
 mart1nN

比如一个 ThreadDemo 类实现了 Runnable 接口,我在 main 函数中创建了一个 ThreadDemo 类实例,并用这个实例创建了两个线程。 当我在 ThreadDemo 中定义了一个 private int count 属性时,请问这个变量在两个线程栈中都有存储吗?还是说这个变量存储在另外的地方?如果我在 ThreadDemo 中定义了 private String name 时又是怎么样的?

2650 次点击
所在节点    Java
17 条回复
momocraft
2019-04-11 14:59:44 +08:00
field 是对象的一部分,一定不在栈上,**对象的引用** 才可能在栈上

这已经和线程没关系了..
misaka19000
2019-04-11 15:07:27 +08:00
上代码
gosansam
2019-04-11 15:15:42 +08:00
个人感觉共享变量存在主存中,各个使用会去拉副本到线程栈
liuxey
2019-04-11 15:19:46 +08:00
首先你的案例里没有资源共享的情况,两个 ThreadDemo 实例都有自己的 count,各不相干
其次 String 也是一样的
gaius
2019-04-11 15:26:59 +08:00
new 一个实例是怎么开的 2 个线程?
lhx2008
2019-04-11 15:30:14 +08:00
栈上面就没有共享的事情
mart1nN
2019-04-11 15:45:02 +08:00
ThreadDemo

public class ThreadDemo implements Runnable{

private int count;

public ThreadDemo() {
count = 0;
}

@Override
//循环打印
public void run() {
System.out.println("before syn");
synchronized (this){
for (int i = 0; i < 10; i++){
try {
System.out.println(Thread.currentThread().getName() + ":" + (count++));
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("after syn");
}

}


test

//这里就写主要部分了
ThreadDemo threadDemo = new ThreadDemo();
Thread t1 = new Thread(threadDemo, "thread-01");
Thread t2 = new Thread(threadDemo, "thread-02");
t1.start();
t2.start();

t1,t2 这两个线程栈里存储了 threadDemo 实例的引用吗?还有就是 main 线程会给这两个线程初始化后这三个线程栈存储的有啥不同吗?
misaka19000
2019-04-11 15:55:35 +08:00
应该只有 main 线程的栈中持有对 threadDemo 对象的引用吧
Michlix
2019-04-11 16:07:31 +08:00
domty
2019-04-11 16:17:37 +08:00
对象都是分配在堆上的
即便是线程持有的也只是这个对象的一个引用
hailiang88
2019-04-11 16:29:26 +08:00
1、如果是类的成员变量的话会存在 Method Area,这个区域是线程共享的
2、如果是局部变量的话会存在于 Stack Area,可以了解下栈帧( stack frame ),这个是线程私有的
[https://liang.im/index.php/archives/3/]( https://liang.im/index.php/archives/3/)
DanielGuo
2019-04-11 16:30:51 +08:00
@mart1nN 在我的理解中,t1 和 t2 都是一个对象,这两个对象都在堆中存在,t1 和 t2 的实例变量有对 threadDemo 的引用
zifangsky
2019-04-11 17:55:25 +08:00
1、堆、栈的概念跟线程没有关系。
2、对象在堆空间( Heap space )实例化,成员变量 count 自然也在堆空间中,且 new 一次只实例化一次。
3、之所以多个线程对成员变量 count 执行写操作会有线程安全问题,那是因为多个线程在对同一片内存区域的 count 变量进行操作。
v2qwsdcv
2019-04-11 19:45:03 +08:00
源码给您找好啦,求别鄙视我们做 C++的了 都不容易。


https://github.com/unofficial-openjdk/openjdk/blob/5ec14c8bb2533c20eca3564258c4dc66bf3bb9c3/src/java.base/share/classes/java/lang/Thread.java
public synchronized void start() {
...
try {
start0();
started = true;
} ...
}

private native void start0();

https://github.com/unofficial-openjdk/openjdk/blob/531ef5d0ede6d733b00c9bc1b6b3c14a0b2b3e81/src/java.base/share/native/libjava/Thread.c
{"start0", "()V", (void *)&JVM_StartThread},

https://github.com/unofficial-openjdk/openjdk/blob/e19d12112815026f04a9df075e56eb26622b9d8d/src/hotspot/share/prims/jvm.cpp

JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_StartThread");
JavaThread *native_thread = NULL;
...
native_thread = new JavaThread(&thread_entry, sz);

if (native_thread->osthread() != NULL) {
// Note: the current thread is not being used within "prepare".
native_thread->prepare(jthread);
}
}
}
...
Thread::start(native_thread);

JVM_END

static void thread_entry(JavaThread* thread, TRAPS) {
HandleMark hm(THREAD);
Handle obj(THREAD, thread->threadObj());
JavaValue result(T_VOID);
JavaCalls::call_virtual(&result,
obj,
SystemDictionary::Thread_klass(),
vmSymbols::run_method_name(),
vmSymbols::void_method_signature(),
THREAD);
}

https://github.com/unofficial-openjdk/openjdk/blob/294d2d319b870ac68ca10a5b03006a70e26bcaba/src/hotspot/share/runtime/thread.cpp
void JavaThread::run() {
...
thread_main_inner();
}


void JavaThread::thread_main_inner() {
...
if (!this->has_pending_exception() &&
!java_lang_Thread::is_stillborn(this->threadObj())) {
{
ResourceMark rm(this);
this->set_native_thread_name(this->get_thread_name());
}
HandleMark hm(this);
this->entry_point()(this, this);
}
...
}

https://github.com/unofficial-openjdk/openjdk/blob/d148cecb01572f077179c94cb59117af89eb59b8/src/hotspot/share/runtime/javaCalls.cpp

https://github.com/unofficial-openjdk/openjdk/blob/e836a10c8c6ed2ef2f3219c46ca1906a2d9d6493/src/hotspot/share/classfile/vmSymbols.hpp
template(run_method_name, "run")
v2qwsdcv
2019-04-11 20:01:10 +08:00
另 #13 说的对
troywinter
2019-04-12 00:32:12 +08:00
看了这个帖子我还以为搞了十年的 PLT 都是假的,直到看到了#13 楼
gramyang
2019-04-13 08:37:01 +08:00
兄啊,刚刚测试了一下,这个 demo 并不会出现乱序

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

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

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

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

© 2021 V2EX