首页>>后端>>java->Java多线程专题之进阶学习Thread(含源码分析)

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

时间:2023-12-07 本站 点击:0

前言

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

适合人群

有一定的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();

实际输出:

hello2hello3hello1

可以看到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 Thread(Runnable target) {      init(null, target, "Thread-" + nextThreadNum(), 0);  }  Thread(Runnable target, AccessControlContext acc) {      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);  }   ....0

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

join

join():使当前线程等待另一个线程执行完毕之后再继续执行,内部调用的是Object类的wait方法实现的;这个需要大家好好理解

 public Thread(Runnable target) {      init(null, target, "Thread-" + nextThreadNum(), 0);  }  Thread(Runnable target, AccessControlContext acc) {      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);  }   ....1

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

 public Thread(Runnable target) {      init(null, target, "Thread-" + nextThreadNum(), 0);  }  Thread(Runnable target, AccessControlContext acc) {      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);  }   ....2

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

 public Thread(Runnable target) {      init(null, target, "Thread-" + nextThreadNum(), 0);  }  Thread(Runnable target, AccessControlContext acc) {      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);  }   ....3

实际输出

 public Thread(Runnable target) {      init(null, target, "Thread-" + nextThreadNum(), 0);  }  Thread(Runnable target, AccessControlContext acc) {      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);  }   ....2

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

 public Thread(Runnable target) {      init(null, target, "Thread-" + nextThreadNum(), 0);  }  Thread(Runnable target, AccessControlContext acc) {      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);  }   ....5

发现内部是调了一个join方法

 public Thread(Runnable target) {      init(null, target, "Thread-" + nextThreadNum(), 0);  }  Thread(Runnable target, AccessControlContext acc) {      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);  }   ....6

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

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

isAlive()方法是一个native方法

 public Thread(Runnable target) {      init(null, target, "Thread-" + nextThreadNum(), 0);  }  Thread(Runnable target, AccessControlContext acc) {      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);  }   ....7

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

wait 也是一个native方法:

 public Thread(Runnable target) {      init(null, target, "Thread-" + nextThreadNum(), 0);  }  Thread(Runnable target, AccessControlContext acc) {      init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);  }   ....8

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

结束语

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

下期预告

有时候,我们需要异步获取数据,我们之前给大家讲的都是线程执行完就结束了,那么我想获去结果怎么实现呢❓ 下期就带大家学习Callable、Future与FutureTask。关注公众号加群,一起学习进步。关注我,不迷路, 下期不见不散 ~

更文时间

工作日(周一 ? 周五)

周末不更 ☀️

节假日不定时更

往期内容

Java多线程专题之线程与进程概述

Java多线程专题之线程类和接口入门

我的博客(阅读体验较佳)

写给初学者的Java基础教程

一文带你快速学习Java集合类

花几分钟快速了解一下泛型与枚举

Java注解与反射入门到进阶

JavaIO教程从入门到进阶

项目源码(源码已更新 欢迎star⭐️)

java-thread-all

地址: https://github.com/qiuChengleiy/java-thread-all.git

推荐 SpringBoot & SpringCloud (源码已更新 欢迎star⭐️)

springboot-all

地址: https://github.com/qiuChengleiy/springboot-all.git

SpringBoot系列教程合集

一起来学SpringCloud合集

原文:https://juejin.cn/post/7103407297023442951


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/java/18689.html