Java【多线程】Thread类常见方法

目录

[启动一个线程 start()](#启动一个线程 start())

中断一个线程

方式1.通过共享的标记来进行沟通

方式2.调用interrupt()方法来通知

[等待一个线程 join()](#等待一个线程 join())

休眠当前线程


启动一个线程 start()

java标准库/jvm提供的方法

本质上是调用操作系统的api

这样的方法没有实现,只有一个声明

native 本地方法

jvm是c++来写的

带有native的方法实现是在jvm内部通过c++代码来实现的

(要想看到这部分代码需要额外下载jvm的源码c++)

在c++的实现中内部就会判断当前是哪个操作系统,并且调用对应系统的api来创建线程

每个Thread对象都只能start一次,日抛

每次想创建一个新的线程,都得创建一个新的Thread对象(不能重复利用)

java中期望Thread对象和操作系统中的线程是一一对应

start是系统调用api


中断一个线程

核心:让线程的入口方法能够尽快结束

"终止"此处让线程直接就停止了不会再恢复了

让线程的入口方法执行完毕,线程就随之结束了

(run方法尽快return)

方式1.通过共享的标记来进行沟通

变量捕获

lambda里面希望使用外面的变量

触发"变量捕获"这样的语法

lambda是回调函数

执行时机是很久之后(操作系统真正创建出线程之后才会执行)

很有可能,后续线程创建好了。当前main这里的方法都执行完了,对应的isFinished就销毁了

为了解决上述 的问题

java的做法是,把被捕获的变量给拷贝一份,拷贝给lambda里面

外面的变量是否销毁就不影响lambda里面的执行了

拷贝,意味着,这样的变量就不适合进行修改

修改一方,另一方就不会随之变化的(本质上是两个变量)

这种一边变,一边不变可能给程序员带来更多困惑

java大佬们就想了个办法压根不允许你这里进行修改


把上述代码改成成员变量

此时不再是"变量捕获"语法

而是切换成"内部类访问外部类成员"语法

java 复制代码
public class Demo10 {
    private static boolean isFinished = false;
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while(!isFinished){
                System.out.println("hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("Thread 结束");
        });
        t.start();
        Thread.sleep(3000);
        isFinished = true;
    }
}

lamabda本质上是函数式接口

相当于一个内部类

isFinished变量本身就是外部类 (Demo10)的成员

成员变量生命周期也是让GC来管理的

在lambda里面不担心变量生命周期失效的

也就不必拷贝,也就不必限制final之类的

GC==垃圾回收


方式2.调用interrupt()方法来通知

线程终止

java的Thread对象中提供了现成的变量,直接进行判定,不需要自己创建了

java 复制代码
public class Demo11 {
    public static void main(String[] args) throws InterruptedException {
        Thread t =new Thread(()->{
            while(!Thread.currentThread().isInterrupted()){
                System.out.println("hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {

                    break;
                }
            }
            System.out.println("t结束");
        });
       t.start();
       Thread.sleep(3000);
        System.out.println("main线程尝试终止t线程");
       t.interrupt();
    }
}

Thread.currentThread().isInterrupted()判断线程是否被终止了

t.interrupt();主动去进行终止

修改这个boolean变量的值

除了设置boolean变量(标志位)之外

还能够唤醒像sleep这样的阻塞方法

这个操作能够唤醒sleep

sleep会抛出异常

针对异常的处理,使用break结束循环

如果不加上述break(空着的)

针对上述代码

其实是sleep在搞鬼

正常来说,调用Interrupt方法就会修改isInterrupted方法内部的标志位设为true

由于上述代码中,是把sleep给唤醒了

这种提前唤醒的情况下sleep就会在唤醒之后,把isInterrupted标志位设置回false

因此在这样的情况下如果继续执行到循环的条件判定,就会发现能够继续执行

sleep这样设定之后相当于让程序员在catch语句中有更多的选择空间

程序员可以自行决定这个线程是要立即结束还是等会再结束还是不结束

加上break就是立即终止

啥都不写就是不终止

catch中先执行一些其他逻辑再break,就是稍后终止

java中线程的终止不是一个强制性的措施

不是main让t终止t就一定终止,选择权在t自己手上(看t线程自己的代码咋写)

java这里的设定,把决定权交给被终止的线程自己了

线程内部代码中就可以保证,一定是执行出一些"阶段性"的结果,然后才真正退出


上述这里抛出异常的方法不只是sleep会有

等待一个线程 join()

多个线程之间 并发执行 随机调度

join能够要求,多个线程之间,结束的先后顺序

比如。再主线程中调用t.join()

就是让主线程等待t线程先结束

java 复制代码
public class Demo12 {
    public static void main(String[] args) throws InterruptedException {
        Thread t =new Thread(()->{
            for (int i = 0; i < 3; i++) {
                System.out.println("hello Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("t线程结束");
        });
        t.start();

        t.join();
        System.out.println("main线程结束");
    }
}

在main线程中调用t.join

效果:让main线程等待t先结束

当执行到t.jion此时main线程就会"阻塞等待"

一直等到t线程执行完毕,join才能继续执行

不见不散,只要t不结束main的join就会一直等下去

join提供了带参数的版本,指定"超时时间"等待的最大时间

带有超时时间的等待才是更科学的做法

哪个线程调用这个方法返回哪个线程的引用(类似于this)


休眠当前线程

因为线程的调度是不可控的所以这个方法只能保证实际休眠时间是大于等于参数设置的休眠时间

sleep

写了sleep1000很可能比1000略多一点

代码调用sleep相当于让当前线程让出cpu的资源

后续时间到了的时候需要操作系统内核把这个线程重新调到cpu上才能继续执行

时间到意味着允许被调度了

而不是立即就执行了

sleep(0)使用sleep的特殊写法

写了sleep(0)意味着让当前的线程放弃cpu资源(把cpu让出来给别人更多的执行机会,等待操作系统重新调度

相关推荐
梦想科研社3 分钟前
【无人机设计与控制】红嘴蓝鹊优化器RBMO求解无人机路径规划MATLAB
开发语言·matlab·无人机
除了菜一无所有!4 分钟前
基于SpringBoot技术的教务管理
java·spring boot·后端
混迹网络的权某6 分钟前
每天一道C语言精选编程题之求数字的每⼀位之和
c语言·开发语言·考研·算法·改行学it·1024程序员节
lexusv8ls600h1 小时前
微服务设计模式 - 断路器模式 (Circuit Breaker Pattern)
java·微服务·设计模式
逸狼1 小时前
【JavaEE初阶】网络原理(2)
java·网络·java-ee
甲柒1 小时前
12-Docker发布微服务
java·docker·微服务
一只特立独行的猪6111 小时前
Java面试题——微服务篇
java·开发语言·微服务
浅念同学1 小时前
JavaEE-多线程上
java·java-ee
liuyang-neu3 小时前
力扣 简单 70.爬楼梯
java·算法·leetcode
喵手3 小时前
Java 与 Oracle 数据泵实操:数据导入导出的全方位指南
java·开发语言·oracle