zoukankan      html  css  js  c++  java
  • Thread类线程结束会唤醒使用其对象做锁而睡眠的线程

    首先回顾一下我们的基础知识。

    sleep:

      线程睡眠,不会释放锁

    wait:

      线程等待。释放锁。

    notity:

      唤醒随机一个当前对象等待的线程,并不会释放锁

    notityAll:

      唤醒所有当前对象等待的线程,并不会释放锁

    遇到问题:

      代码如下:

      

    package com.zhen.ten_chapter.question;
    
    /**
     * @author zhen
     * @Date 2019/4/18 10:17
     */
    public class ThreadDemo {
        public static void main(String[] args) {
            To10X tos = new To10X(1, 10);
            tos.start();
            int res = tos.getResult();
            System.out.println(res);
    
        }
    
       static class To10X extends Thread {
           
            private int point = 1;
            private int end = 10;
    
            private int result = 0;
    
            public To10X(int start, int end) {
                this.point = start;
                this.end = end;
                
            }
    
            @Override
            public  synchronized void run() {
                
                    while (point != end + 1) {
                        result += point++;
                        System.out.println(Thread.currentThread().getName() + "::" + result);
                    }
                    this.notify();
            }
    
            public  synchronized int getResult() {
                 
                    while(result == 0) {
                        try {
                            System.out.println("锁定前");
                            this.wait();
                            System.out.println("锁定后");
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
    
                return result;
            }
        }
    }
    

      程序发现wait总是会被唤醒。

      怀疑是不是总是先wait然后再被notity了,于是将notify注释掉了,但依然被唤醒。

    什么原因?

      我关注点放在了static关键字上了,依稀记得static 方法的锁锁对象是类,那么static类里面的成员方法的锁对象是不是也是类呢?

        当然是我多想了,但是我依然将static 的内部类改为了一个普通内部类,然后用实例化对象去创建的对应对象与执行方法。可是结果依旧是一样。

      我接下来怀疑是主线程的原因

          因为其他线程都是从主线程上衍生出来的,线程不是很熟练,依稀记得一些所谓守护线程等概念。于是简单写了一个Demo类,主线程wait,然后开一个线程获取到锁执行到结束,然后发现能wait住主线程

    那是什么原因呢?

      接下来我觉得一定是有什么东西唤醒了主线程,notity被我注释掉了,notityAll没有编写。查看wait的api,发现它没有自动唤醒的说法,有一个参数是延迟等待的意思。它明确声明了只能靠notity和notifyAll唤醒。百度大法好。我狂百度,发现有人遇到和我一样的问题,参考链接:  https://blog.csdn.net/nmyangym/article/details/7850882#commentBox 。为此,我也去看了一下所谓的jdk的Thread类的join源码,如下:

      public final synchronized void join(long millis)
        throws InterruptedException {
            long base = System.currentTimeMillis();
            long now = 0;
    
            if (millis < 0) {
                throw new IllegalArgumentException("timeout value is negative");
            }
    
            if (millis == 0) {
                while (isAlive()) {
                    wait(0);
                }
            } else {
                while (isAlive()) {
                    long delay = millis - now;
                    if (delay <= 0) {
                        break;
                    }
                    wait(delay);
                    now = System.currentTimeMillis() - base;
                }
            }
        }
    

      它确实调用了wait,但是调用了wait能保证唤醒吗?我感觉方向没问题了,继续针对点去百度

    参考链接:

      https://segmentfault.com/q/1010000016744022?utm_source=tag-newest

      原来,Thread对象在线程结束的时候,会自动调用一次notifyAll语法,线程结束会执行join方法,join的jdk写法我们看到过,大牛给出的依据是openJDK中的源码:

    int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
    
    static void *java_start(Thread *thread) {
      ...
      thread->run();
      return 0;
    }
    
    void JavaThread::run() {
      ...
      thread_main_inner();
    }
    
    void JavaThread::thread_main_inner() {
      ...
      this->exit(false);
      delete this;
    }
    
    void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
      ...
      // Notify waiters on thread object. This has to be done after exit() is called
      // on the thread (if the thread is the last thread in a daemon ThreadGroup the
      // group should have the destroyed bit set before waiters are notified).
      ensure_join(this);
      ...
    }
    
    static void ensure_join(JavaThread* thread) {
      // We do not need to grap the Threads_lock, since we are operating on ourself.
      Handle threadObj(thread, thread->threadObj());
      assert(threadObj.not_null(), "java thread object must exist");
      ObjectLocker lock(threadObj, thread);
      // Ignore pending exception (ThreadDeath), since we are exiting anyway
      thread->clear_pending_exception();
      // Thread is exiting. So set thread_status field in  java.lang.Thread class to TERMINATED.
      java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
      // Clear the native thread instance - this makes isAlive return false and allows the join()
      // to complete once we've done the notify_all below
      java_lang_Thread::set_thread(threadObj(), NULL);
      lock.notify_all(thread);
      // Ignore pending exception (ThreadDeath), since we are exiting anyway
      thread->clear_pending_exception();
    }
    

      

     

    结论:

      尽量不要用线程对象做同步锁的钥匙,线程结束的时候它会自动调用this.notifyAll()

  • 相关阅读:
    Python反射机制
    并发和并行的区别
    I/O模型
    python 字符串零散方法记录
    python 关于占位符格式化
    Python 十进制转二进制、八进制、十六进制
    python中str函数isdigit、isdecimal、isnumeric的区别
    文件的修改
    LF 模块三
    stackoverflow os.path.abspath and os.path.realpath
  • 原文地址:https://www.cnblogs.com/aigeileshei/p/10728739.html
Copyright © 2011-2022 走看看