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

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

Thread类线程结束会唤醒使用其对象做锁而睡眠的线程的更多相关文章

  1. java基础知识回顾之java Thread类学习(四)--java多线程安全问题(锁)

    上一节售票系统中我们发现,打印出了错票,0,-1,出现了多线程安全问题.我们分析为什么会发生多线程安全问题? 看下面线程的主要代码: @Override public void run() { // ...

  2. java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提

    这里举个例子讲解,同步synchronized在什么地方加,以及同步的前提: * 1.必须要有两个以上的线程,才需要同步. * 2.必须是多个线程使用同一个锁. * 3.必须保证同步中只能有一个线程在 ...

  3. Java多线程系列--“基础篇”05之 线程等待与唤醒

    概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long t ...

  4. java 多线程—— 线程等待与唤醒

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  5. Java多线程5:线程等待与唤醒

    原文:http://www.cnblogs.com/skywang12345/p/3479224.html wait(),notify(), notifyAll()等方法介绍在Object.java中 ...

  6. Java多线程(五)——线程等待与唤醒

    一.wait().notify().notifyAll()等方法介绍 在Object.java中,定义了wait(), notify()和notifyAll()等接口.wait()的作用是让当前线程进 ...

  7. java - 线程等待与唤醒

    Java多线程系列--“基础篇”05之 线程等待与唤醒 概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. w ...

  8. java 多线程系列基础篇(五)之线程等待与唤醒

    1.wait(), notify(), notifyAll()等方法介绍 在Object.java中,定义了wait(), notify()和notifyAll()等接口.wait()的作用是让当前线 ...

  9. Java 多线程基础(六)线程等待与唤醒

    Java 多线程基础(六)线程等待与唤醒 遇到这样一个场景,当某线程里面的逻辑需要等待异步处理结果返回后才能继续执行.或者说想要把一个异步的操作封装成一个同步的过程.这里就用到了线程等待唤醒机制. 一 ...

随机推荐

  1. 20165306 Exp2 后门原理与实践

    20165306 Exp2 后门原理与实践 实验内容 (1)使用netcat获取主机操作Shell,cron启动 (2)使用socat获取主机操作Shell, 任务计划启动 (3)使用MSF mete ...

  2. React点击操作自动定位到另外一个元素

    使用Ref 方式一 使用ScrollIntoView方法 import React from 'react' export default class ScrollToElement extends ...

  3. 防cc攻击策略

    黑客攻击你的网站,会采取各种各样的手段,其中为了降低你网站的访问速度,甚至让你的服务器瘫痪,它会不断的刷新你的网站,或者模拟很多用户同一时间大量的访问你的网站, 这就是所谓的CC攻击,这就需要我们在程 ...

  4. 【GO】【环境配置】

    1.首先下载GO的安装包:https://golang.org/doc/install#testing 找到上面一个Download超大按钮,找不到的可以不用再看了. 下载完成,安装. 安装成功后,启 ...

  5. 编译原理中DFA最小化

    关于编译原理最小化的操作,专业术语请移步至:http://www.360doc.com/content/18/0601/21/11962419_758841916.shtml 这里只是记录一下个人的理 ...

  6. suse源

    zypper addrepo -f http://mirrors.vbi.vt.edu/mirrors/linux/opensuse/discontinued/distribution/11.4/re ...

  7. oracle 12 c 创建表空间,用户名,及表

      -----------------------------------------12C start------------------------------------------- -- 创 ...

  8. ArcSDE10.1配置Oracle 监听器来使用SQL操作ST_Geometry(个人改动版)

    发了两天的时间来解决配置Oracle 监听器来使用SQL操作ST_Geometry的配置,网上搜索一大片,结果真正找到的只有方法可用,下面把这个方法我个人在总结下. ArcSDE10.1配置Oracl ...

  9. 记一次mybatis bindingexception 问题排查

    看到的错误信息如出一辙都是这样的:Method threw 'org.apache.ibatis.binding.BindingException' exception.Invalid bound s ...

  10. ArcGIS中删除“点”附带的对应“文本信息”

    现状: 用ArcMap打开对应的.mxd文件,导入KML数据后,几何类型“点” - 每一个点都附带对应的文本信息“Placemark”,如下图: 问题:ArcGIS中如何 删除“点”附带的对应“文本信 ...