Java 多线程专题之进阶学习 Thread(含源码分析)

Multisim仿真电路:(十二)MOS管缓启动电路设计与优化 本文详细介绍了基于Multisim的MOS管缓启动电路设计与优化方法。通过分析米勒平台效应,探讨RC参数选择、多级设计和有源电路等技巧,有效抑制冲击电流并优化开关损耗。文章结合仿真实例,提供实用的设计策略和实际应用注意事项,帮助工程师提升电源管理系统的可靠性。 阅读详情

前言

大家好,一直以来我都本着用最通俗的话理解核心的知识点, 我认为所有的难点都离不开 基础知识 的铺垫。目前正在出一个 Java多线程专题 长期系列教程,从入门到进阶, 篇幅会较多, 喜欢的话,给个关注:heart: ~

适合人群

  • 有一定的Java基础
  • 想学习或了解多线程开发
  • 想提高自己的同学

大佬可以绕过 ~

背景

之前给大家讲了一些 框架 的使用,这些都属于业务层面的东西,你需要熟练掌握它并在项目中会运用它即可,但这些对自身技术的积累是远远不够的,如果你想要提高自己,对于语言本身你需要花更多的时间去挖掘而不是局限于框架的使用,所以之前为什么跟大家一直强调 基础 的重要性,框架可以千变万化,层出不穷,但是基础它是不变的,不管是学 java 还是 前端 或者是其它语言, 这一点大家还是需要认清的。

接下来的几期会专门讲 多线程 这一块,篇幅会较多,耐心看完你一定会有 收获 ~

情景回顾

上期带大家学习了什么是入门学习了 Thread类和Runable接口 ,本期带大家进阶学习 Thread 的用法,我们一起来看一下吧~

Thread类的常用方法

在了解之前,我们先看下它的初始化方法

构造函数

  • 无参数
public Thread() {
      init(null, null, "Thread-" + nextThreadNum(), 0);
  }
复制代码
  • 有参数
public Thread(Runnable target) {
      init(null, target, "Thread-" + nextThreadNum(), 0);
  }

  Thread(Runnable target, AccessControlContext acc) {
      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
  }
   .... 
复制代码

其实我们从源码可以发现,构造函数内部,都调用了初始化方法 init

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
                        ...
}
复制代码

其实要给大家讲的是它这几个参数的意思,可以了解一下

  • g 线程组,指定这个线程是在哪个线程组下

  • target target:指定要执行的任务

  • name 线程的名字,多个线程的名字是可以重复的

  • acc 用于初始化私有变量 inheritedAccessControlContext

  • inheritThreadLocals 可继承的 ThreadLocal

这个大家了解下就行, 下面我们看看常用的方法

currentThread

  • currentThread() :native静态方法,返回对当前正在执行的线程对象的引用;
public static native Thread currentThread();
复制代码
public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("hello");
        });
        System.out.println(t.currentThread());
        t.start();
        System.out.println(t.currentThread());
}
复制代码

输出

Thread[main,5,main]
Thread[main,5,main]
hello
复制代码

start

  • start() :开始执行线程的方法,java虚拟机会调用线程内的run()方法;
public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
复制代码

同时会加入线程组,这里执行的 start0(); 是一个 native 方法

yield

  • yield() 指的是当前线程愿意让出对当前处理器的占用,这个怎么理解呢,看一个例子
Thread t = new Thread(() -> {
    Thread.yield();
    System.out.println("hello1");
});

Thread t1 = new Thread(() -> {
    System.out.println("hello2");
});

Thread t2= new Thread(() -> {
    System.out.println("hello3");
});


t.start();
t1.start();
t2.start();
复制代码

实际输出:

hello2
hello3
hello1
复制代码

可以看到 t 调用了 yield 方法,最后输出,我们大体可以猜到,线程 t 让步,线程 t1 先抢到cpu实际开始执行所以, hello2 先输出

sleep

  • sleep() :native静态方法,使当前线程睡眠一段时间,单位是 ms, 类似js的 setTimeout ,但sleep非异步,会阻塞当前线程
public static native void sleep(long millis) throws InterruptedException;
复制代码

其实还有一个非native的方法,但是内部调的还是native, 可以用于指定时间范围内的休眠

public static void sleep(long millis, int nanos)
throws InterruptedException {
    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException(
                            "nanosecond timeout value out of range");
    }

    if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
        millis++;
    }

    sleep(millis);
}
复制代码

在很久之前的网站,有些老板会使用骚操作,开会员少休眠几秒,不开会员响应给你慢点

join

  • join():使当前线程等待另一个线程执行完毕之后再继续执行,内部调用的是Object类的 wait 方法实现的;这个需要大家好好理解
public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            System.out.println("hello1");
        });
        t.join();

        Thread t1 = new Thread(() -> {
            System.out.println("hello2");
        });

        Thread t2= new Thread(() -> {
            System.out.println("hello3");
        });


        t.start();
        t1.start();
        t2.start();

    }
复制代码

这里的join是一个实例方法,我们看下时间输出

hello2
hello1
hello3
复制代码

发现t线程在t1线程后执行, 跟我们之前讲的 yield 还不太一样, 虽然也有让步的意思,但是让完就执行了,就是说,等待另一个线程也就是t1执行完再执行, 而 yield 是让出cpu时间片, 那我t2也让一下,是不是t3就先执行了,是这样吗:question:我们来看一下

Thread t = new Thread(() -> {
    System.out.println("hello1");
});
t.join();

Thread t1 = new Thread(() -> {
    System.out.println("hello2");
});
t1.join();

Thread t2= new Thread(() -> {
    System.out.println("hello3");
});


t.start();
t1.start();
t2.start();
复制代码

实际输出

hello2
hello1
hello3
复制代码

发现结果还是没变化,这是怎么回事呢?t1join之后,应该是t3先执行才对,想知道原因还得看它的实现,我们看下源码

public final void join() throws InterruptedException {
      join(0);
  }
复制代码

发现内部是调了一个 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;
        }
    }
}
复制代码

这个方法加了一个 synchronized 同步锁 , synchronized在同一时刻只允许一个线程执行,如果有其它线程执行,需要等待当前线程执行完毕后再执行,具体的用法,后边给大家讲  的时候讲。

这个方法可以传入指定时间,就是说等待n毫秒让该线程终止,如果为 millis为0 ,会先判断线程是否处于存活状态,存在就wait(0)等待0毫秒。如果 millis大于0 ,同样会先判断线程是否处于存活状态,并延迟deplay,当 delay小于等于0 跳出循环,其实循环到这,也相当于等待 millis 时间了,因为这个过程需要一直判断线程的状态

isAlive() 方法是一个native方法

public final native boolean isAlive();
复制代码

如果线程已启动且尚未死亡,则该线程处于活动状态。如果该线程还活着,则为true ;否则false 。

wait 也是一个native方法:

public final native void wait(long timeout) throws InterruptedException;
复制代码

使当前线程等待,直到另一个线程为此对象调用notify()方法或notifyAll()方法,或者经过了指定的时间量。 timeout – 等待的最长时间(以毫秒为单位)。这里其实涉及到 线程状态切换 的知识了,这个我们放到后边讲

结束语

本期到这里就结束了, 总结一下,本节主要讲了 Thread类 的常用方法,建议大家可以自己多试试~

一文告诉你:如何在trae中编译运行GD32程序,并让AI帮你修改代码 本文详细介绍了如何将GD32程序如何用官方固件库构建出来,然后从Keil迁移到国产免费工具Trae,并利用AI进行代码修改的全过程。 阅读详情

相关推荐

从零开始:用ADS仿真设计一个2.4GHz Wi-Fi低噪声放大器(完整电路图)

本文提供了一份详细的ADS软件仿真指南,手把手教你从零开始设计一个2.4GHz Wi-Fi低噪声放大器。内容涵盖核心指标理解、晶体管选型与建模、匹配网络设计、偏置电路集成,并通过S参数仿真、噪声优化及线性度验证等步骤,最终呈现完整的优化电路图,助力射频初学者掌握LNA设计全流程。

weixin_29197835的博客 754

Thread学习

涉及源码的解读暂不在该文章中探究。 1. public static native Thread currentThread():返回该代码段正在被哪个线程调用的信息 2. public final native boolean isAlive():测试线程是否处于活动状态(正在运行或准备运行的状态) 3. 判断线程是否是停止状态 **** /** * Tests whether th...

Mr_moving 259

讲透 ABAP CDS 注解名称:简单名、结构化名、@ 与 @<、作用域与分组

本文从开发者角度梳理ABAP CDS注解的命名规则与实战写法,重点解析: 语法规则:@与@<的使用场景、结构化命名规范、作用域唯一性要求 评估机制:ABAP运行时与组件框架的注解处理差异 分组技巧:花括号分组简化重复前缀的书写 实战示例:包完整CDS View Entity(演示注解分组与@<用法)和ABAP报表(读取打印注解) 常见问题:命名错误导致激活失败、框架忽略等注意事项 最后通过航空预订统计案例,展示如何结合多种注解类型实现业务需求。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 221

Android native Thread实现 和Java Thread区别

Android native Thread实现 和Java Thread区别

yefengxuelang的专栏 1855

public static native Thread currentThread()用本地方法实现获取当前线程,jvm实现

native

jiangxizhe881222的博客 1773

多线程基础(二)---Thread类中常用的方法

Thread类中常用的方法 1、public static native Thread currentThread() 该方法可以返回代码段正在被哪个线程调用的信息。 2、public static native void yield() 暂停线程,让CPU执行其它线程。在正常情况下,线程获得CPU时间片开始执行,当时间片用完后,线程进入可运行状态,CPU切换线程,线程调度器随机地...

maijia0754的博客 487

Java多线程专题进阶学习Thread(源码分析)

进阶学习Thread(源码分析)

m0_71682321的博客 255

Java多线程与高并发专题——在 Thread 中多个 ThreadLocal 是怎么存储的?

Java多线程与高并发专题——在 Thread 中多个 ThreadLocal 是怎么存储的?

从知识输入到知识输出 1668

Runnable和Thread源码分析

Runnable和Thread源码分析 问题的引入: Runnable是一个接口,它只有一个run()抽象方法,run()抽象方法需要被实现后才能使用。Thread类继承了Runnable接口,并且Thread中实现了run()方法。最后,通过Thread类的start()方法就可以启动线程了。这是我们平时在应用中使用线程的常用方法。如果多加思考你会发现以下几个问题: 1、为什么调用start()...

马一凡的博客 1817

Java多线程专题之Callable、Future与FutureTask(源码分析)

目前正在出一个Java多线程专题长期系列教程,从入门到进阶

m0_71682321的博客 182

java多线程Thread join与CountDownLatch源码分析java面试编程题算法及答案

机会是留给有准备的人,大家在求职之前应该要明确自己的态度,熟悉求职流程,做好充分的准备,把一些可预见的事情做好。对于应届毕业生来说,校招更适合你们,因为绝大部分都不会有工作经验,企业也不会有工作经验的需求。同时,你也不需要伪造高大上的实战经验,以此让自己的简历能够脱颖而出,反倒会让面试官有所怀疑。你在大学时期应该明确自己的发展方向,如果你在大一就确定你以后想成为Java工程师,那就不要花太多的时间去学习其他的技术语言,高数之类的,不如好好想着如何夯实Java基础。请转发本文支持一下。

2401_84424990的博客 726

源码分析Java多线程Thread构造函数

最最最基本的知识点 Java应用程序的main函数是一个线程,在JVM启动的时候调用,名字叫main 实现一个线程,必须创建Thread实例,重写run方法。而且必须使用start方法启动,否则只是一个实现类 Thread t1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { System.out....

xzzz2020的博客 1175

java实现多线程的四种方式及多线程源码分析

写在前面 本文描述了java实现多线程的四种方式,文章可能还有很多不足,请大家谅解,欢迎大佬提意见。 本文使用到的东西 eclipse 2019-11 java 文章目录写在前面本文使用到的东西1.继承Thread类1.1实现代码1.2源码分析2.实现Runnable接口2.1实现代码2.2 源码分析3.实现Callable3.1实现代码3.2 Callable源码分析3.3 FutureTa...

玖涯博客 473

Android多线程:请收好这份全面&详细的多线程学习指南!

前言 多线程的应用在Android开发中是非常常见的,常用方法主要有: 今天,我将献上一份全面 & 详细的Android多线程学习指南,希望你们喜欢。 目录 1. 多线程基础知识 在了解Android多线程实现方式前,需了解一些多线程基础知识,如线程、进程等 具体请看文章:Android多线程:你必须要了解的多线程基础知识汇总 2. Android多线程实现方式 ...

Carson带你学Android 5113

Java多线程源码分析学习(一)

Java多线程java编程中最为重要的一部分,学习多线程可以让开发得心应手,话不多说,下面开始进入正题。 线程和进程的区别想必大家都知道了,但我还是想啰嗦一下,,, 首先进程是相对于操作系统来说的,是操作系统执行的最小单位,例如:电脑打开腾旭QQ、微信、Office等,每个程序都占了一个计算器的运行时间,即每个程序就是一个进程。而线程是组成进程的最小的单元,一个进程可以有多个线程,但...

胡子先生ya的博客 923

Thread 和 启动线程几种方式

启动线程几种方式第一种: 1】d定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。 2】创建Thread子类的实例,也就是创建了线程对象 3】启动线程,即调用线程的start()方法 注:(start ()是真正的启用了线程 run() 只是thread类的一个方法) 第二种: A类实现runnable 重写run 方...

有趣的难受 9196

javaSE:不同方式线程创建;线程安全问题

目录 1、线程基本知识: 2、Thread方式创建线程 3、Runnable接口方式创建线程 4、线程安全问题 4.1、同步代码块 4.2、synchronized修饰 1、线程基本知识: /* 1、并发并行: 并发:两个或多个事件在同一时间段内发生 多个事件交替执行 并行:两个或多个事件在同一时刻发生 多个事件同时执行 并行速度快些 2、进程与线程: 线程属于进程,是进程的一个执行单元,负责程序的执行 进程:点击程序,会进入内存中占用内存执行,进入到内存

m0_52338152的博客 504

java输出线程时,显示Thread[main,5,main],中括号里的三个值分别代表什么?

1. 实例代码 public class SpinLockDemo { public static void main(String[] args) { Thread thread = Thread.currentThread(); System.out.println("当前线程名字:"+ thread); } } 2.运行结果 3.说明 [线程名称, 线程优先级, 线程所属线程组] ...

qq_37306041的博客 3572

Spring 源码系列(23): SpringApplication.run() 启动全流程

本文深入解析了SpringApplication.run()的核心流程,通过源码拆解揭示了从启动到容器就绪的完整生命周期。文章重点分析了三个关键阶段:prepareEnvironment的配置加载逻辑(系统属性>环境变量>配置文件)、createApplicationContext的容器类型推断机制(基于classpath判断Web/Reactive/普通应用),以及callRunners的启动后回调特性(按@Order执行初始化任务)。同时澄清了常见误区,如内嵌Tomcat实际在refresh阶段的onR

不才不才不不才的博客 414

Java 并发灵魂拷问:notify/signal 唤醒顺序是规范还是实现?

本文探讨了Java中Object.notify()和Condition.signal()唤醒线程的顺序问题。关键结论如下: Object.notify()JVM规范未规定唤醒顺序,HotSpot实现虽采用FIFO(从WaitSet头部取线程),但这属于实现细节而非规范要求 由于synchronized是非公平锁,被唤醒线程需重新竞争锁,最终执行顺序无法保证 严禁业务代码依赖该顺序 Condition.signal(): 严格按FIFO顺序唤醒(AQS等待队列头部线程) 是设计约定,业务可合理依赖该特性

weixin_68315058的博客 363

[Java]-微服务面试题

服务降级是服务自我保护的一种方式,或者保护下游服务的一种方式,用于确保服务不会受请求突增影响变得不可用,确保服务不会崩溃。微服务的负载均衡主要使用了一个组件Ribbon,比如,我们在使用feign远程调用的过程中,底层的负载均衡就是。2,我们还在skywalking设置了告警规则,特别是在项目上线以后,如果报错,我们分别设置了可以给相关负责人。简历上写的微服务,只要是发生了多个服务之间的写操作,都需要进行分布式事务控制。2,在客户端的配置文件中,可以配置某一个服务调用的负载均衡策略(局部)

. 617

汉江平原矢量范围界线,懂的都懂,欢迎研究使用

汉江平原矢量范围界线,懂的都懂,欢迎研究使用

mysql.exe命令行连接器

mysql命令行连接器,最原始的mysql操作程序

上一篇: 我们总结了弹性伸缩的五个条件与六个教训
下一篇: java韩顺平最新教程,Java工程师进阶
一头狒狒
博客等级 码龄4年 66粉丝 122原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值