Thread類線程結束會喚醒使用其對象作鎖而睡眠的線程

首先回顧一下咱們的基礎知識。java

 

sleep:segmentfault

  線程睡眠,不會釋放鎖api

 

wait:ide

  線程等待。釋放鎖。this

 

notity:spa

  喚醒隨機一個當前對象等待的線程,並不會釋放鎖.net

 

notityAll:線程

  喚醒全部當前對象等待的線程,並不會釋放鎖對象

 

遇到問題:blog

  代碼以下:

  

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()

相關文章
相關標籤/搜索