Java 多线程资源共享的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
mart1nN
V2EX    Java

Java 多线程资源共享的问题

  •  
  •   mart1nN 2019-04-11 14:44:44 +08:00 3103 次点击
    这是一个创建于 2455 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    这已经和线程没关系了..
    misaka19000
        2
    misaka19000  
       2019-04-11 15:07:27 +08:00 via Android
    上代码
    gosansam
        3
    gosansam  
       2019-04-11 15:15:42 +08:00
    个人感觉共享变量存在主存中,各个使用会去拉副本到线程栈
    liuxey
        4
    liuxey  
       2019-04-11 15:19:46 +08:00
    首先你的案例里没有资源共享的情况,两个 ThreadDemo 实例都有自己的 count,各不相干
    其次 String 也是一样的
    gaius
        5
    gaius  
       2019-04-11 15:26:59 +08:00
    new 一个实例是怎么开的 2 个线程?
    lhx2008
        6
    lhx2008  
       2019-04-11 15:30:14 +08:00
    栈上面就没有共享的事情
    mart1nN
        7
    mart1nN  
    OP
       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
        8
    misaka19000  
       2019-04-11 15:55:35 +08:00
    应该只有 main 线程的栈中持有对 threadDemo 对象的引用吧
    Michlix
        9
    Michlix  
       2019-04-11 16:07:31 +08:00
    domty
        10
    domty  
       2019-04-11 16:17:37 +08:00
    对象都是分配在堆上的
    即便是线程持有的也只是这个对象的一个引用
    hailiang88
        11
    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
        12
    DanielGuo  
       2019-04-11 16:30:51 +08:00
    @mart1nN 在我的理解中,t1 和 t2 都是一个对象,这两个对象都在堆中存在,t1 和 t2 的实例变量有对 threadDemo 的引用
    zifangsky
        13
    zifangsky  
       2019-04-11 17:55:25 +08:00
    1、堆、栈的概念跟线程没有关系。
    2、对象在堆空间( Heap space )实例化,成员变量 count 自然也在堆空间中,且 new 一次只实例化一次。
    3、之所以多个线程对成员变量 count 执行写操作会有线程安全问题,那是因为多个线程在对同一片内存区域的 count 变量进行操作。
    v2qwsdcv
        14
    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
        15
    v2qwsdcv  
       2019-04-11 20:01:10 +08:00
    另 #13 说的对
    troywinter
        16
    troywinter  
       2019-04-12 00:32:12 +08:00
    看了这个帖子我还以为搞了十年的 PLT 都是假的,直到看到了#13 楼
    gramyang
        17
    gramyang  
       2019-04-13 08:37:01 +08:00
    兄啊,刚刚测试了一下,这个 demo 并不会出现乱序
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2808 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 39ms UTC 14:39 PVG 22:39 LAX 06:39 JFK 09:39
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86