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()
Thread类线程结束会唤醒使用其对象做锁而睡眠的线程的更多相关文章
- java基础知识回顾之java Thread类学习(四)--java多线程安全问题(锁)
上一节售票系统中我们发现,打印出了错票,0,-1,出现了多线程安全问题.我们分析为什么会发生多线程安全问题? 看下面线程的主要代码: @Override public void run() { // ...
- java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提
这里举个例子讲解,同步synchronized在什么地方加,以及同步的前提: * 1.必须要有两个以上的线程,才需要同步. * 2.必须是多个线程使用同一个锁. * 3.必须保证同步中只能有一个线程在 ...
- Java多线程系列--“基础篇”05之 线程等待与唤醒
概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long t ...
- java 多线程—— 线程等待与唤醒
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程5:线程等待与唤醒
原文:http://www.cnblogs.com/skywang12345/p/3479224.html wait(),notify(), notifyAll()等方法介绍在Object.java中 ...
- Java多线程(五)——线程等待与唤醒
一.wait().notify().notifyAll()等方法介绍 在Object.java中,定义了wait(), notify()和notifyAll()等接口.wait()的作用是让当前线程进 ...
- java - 线程等待与唤醒
Java多线程系列--“基础篇”05之 线程等待与唤醒 概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. w ...
- java 多线程系列基础篇(五)之线程等待与唤醒
1.wait(), notify(), notifyAll()等方法介绍 在Object.java中,定义了wait(), notify()和notifyAll()等接口.wait()的作用是让当前线 ...
- Java 多线程基础(六)线程等待与唤醒
Java 多线程基础(六)线程等待与唤醒 遇到这样一个场景,当某线程里面的逻辑需要等待异步处理结果返回后才能继续执行.或者说想要把一个异步的操作封装成一个同步的过程.这里就用到了线程等待唤醒机制. 一 ...
随机推荐
- 打包发布Python模块或程序,安装包
Python模块.扩展和应用程序可以按以下几种形式进行打包和发布: python setup.py获取帮助的方式 python setup.py --help python setup.py --he ...
- acm:屁屁上的巴掌
涉及算法:深度搜索 题目: 题目描述 小新是个调皮的孩子,他总是会把衣服搞脏,他的妈妈美伢非常的生气,于是在<和妈妈的约定条款>加上了第三百七十七条:小新衣服上每有一块污渍妈妈就会打小新的 ...
- TreeMap/LinkedHashMap/HashMap按键排序和按值排序
今天做统计时需要对X轴的地区按照地区代码(areaCode)进行排序,由于在构建XMLData使用的map来进行数据统计的,所以在统计过程中就需要对map进行排序. 一.简单介绍Map 在讲解Map排 ...
- 雷林鹏分享:jQuery EasyUI 数据网格 - 自定义分页
jQuery EasyUI 数据网格 - 自定义分页 数据网格(datagrid)内置一个很好特性的分页功能,自定义也相当简单.在本教程中,我们将创建一个数据网格(datagrid),并在分页工具栏上 ...
- DS博客作业01--日期抽象数据类型设计与实验
1.思维导图及学习体会(2分) 1.1第一章绪论知识点思维导图 1.2 学习体会 2.大作业作业内容 (6分) 2.1 设计日期的ADT类型(1分) ADT DATE{ 数据对象:D={year,mo ...
- 微信小程序分包跳转主包页面
由于公司项目比较多,我们事业部的微信小程序就在一个分包里.那分包页面要回到主包的首页,该怎么跳转呢,有以下两种方法 wx.switchTab(Object object) 跳转到 tabBar 页面, ...
- ajax提交不进入后台报415错误
Unsupported Media Type错误 问题所在为后台缺包和xml配置文档缺配置或配置不正确: Jackson的依赖问题,spring3.x和spring4.x是不同的: spring3.x ...
- 记MySQL的一次查询经历
今天在MySQL查数据,sql语句如下: SELECT * FROM `admins` where dep_ids = 24;
- sql server error 53
主要是计算机名修改了,通过服务器名称,浏览更多,选择“数据库引擎”里面的第一个,就可以登陆了
- 有价值的IPFS博客
前一阵子研究IPFS,回头找资料有些找不到,再次汇总一下有价值的IPFS资料 戴嘉乐-IPFS的本质架构及应用:https://blog.csdn.net/u012357002/article/d ...