mart1nN
V2EX  ›  Java

Java 多线程资源共享的问题

  •  
  •   mart1nN · Apr 11, 2019 · 3337 views
    This topic created in 2617 days ago, the information mentioned may be changed or developed.

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

    17 replies    2019-04-13 08:37:01 +08:00
    momocraft
        1
    momocraft  
       Apr 11, 2019
    field 是对象的一部分,一定不在栈上,**对象的引用** 才可能在栈上

    这已经和线程没关系了..
    misaka19000
        2
    misaka19000  
       Apr 11, 2019 via Android
    上代码
    gosansam
        3
    gosansam  
       Apr 11, 2019
    个人感觉共享变量存在主存中,各个使用会去拉副本到线程栈
    auin
        4
    auin  
       Apr 11, 2019
    首先你的案例里没有资源共享的情况,两个 ThreadDemo 实例都有自己的 count,各不相干
    其次 String 也是一样的
    gaius
        5
    gaius  
       Apr 11, 2019
    new 一个实例是怎么开的 2 个线程?
    lhx2008
        6
    lhx2008  
       Apr 11, 2019
    栈上面就没有共享的事情
    mart1nN
        7
    mart1nN  
    OP
       Apr 11, 2019
    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
        8
    misaka19000  
       Apr 11, 2019
    应该只有 main 线程的栈中持有对 threadDemo 对象的引用吧
    Michlix
        9
    Michlix  
       Apr 11, 2019
    domty
        10
    domty  
       Apr 11, 2019
    对象都是分配在堆上的
    即便是线程持有的也只是这个对象的一个引用
    hailiang88
        11
    hailiang88  
       Apr 11, 2019
    1、如果是类的成员变量的话会存在 Method Area,这个区域是线程共享的
    2、如果是局部变量的话会存在于 Stack Area,可以了解下栈帧( stack frame ),这个是线程私有的
    [https://liang.im/index.php/archives/3/]( https://liang.im/index.php/archives/3/)
    DanielGuo
        12
    DanielGuo  
       Apr 11, 2019
    @mart1nN 在我的理解中,t1 和 t2 都是一个对象,这两个对象都在堆中存在,t1 和 t2 的实例变量有对 threadDemo 的引用
    zifangsky
        13
    zifangsky  
       Apr 11, 2019
    1、堆、栈的概念跟线程没有关系。
    2、对象在堆空间( Heap space )实例化,成员变量 count 自然也在堆空间中,且 new 一次只实例化一次。
    3、之所以多个线程对成员变量 count 执行写操作会有线程安全问题,那是因为多个线程在对同一片内存区域的 count 变量进行操作。
    v2qwsdcv
        14
    v2qwsdcv  
       Apr 11, 2019
    源码给您找好啦,求别鄙视我们做 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
        15
    v2qwsdcv  
       Apr 11, 2019
    另 #13 说的对
    troywinter
        16
    troywinter  
       Apr 12, 2019
    看了这个帖子我还以为搞了十年的 PLT 都是假的,直到看到了#13 楼
    gramyang
        17
    gramyang  
       Apr 13, 2019
    兄啊,刚刚测试了一下,这个 demo 并不会出现乱序
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3142 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 101ms · UTC 13:00 · PVG 21:00 · LAX 06:00 · JFK 09:00
    ♥ Do have faith in what you're doing.