多线程基础保姆级教程

多线程基础

中断一个线程

通常使用Thread.currentThread().isInterrupted() t.isInterrupted()配合使用来中断一个线程

currentThread()方法用来获取当前线程的是咧,哪个线程调用就返回哪个线程的对象。

Thread内部有一个标志位,这个标志位就可以用来判断线程是否结束
上篇讲到了,手动设置标志位,当线程内部在sleep的时候,主线程修改变量,新线程不能及时响应

而t.interrupt()就可以把Thread内部的这个标志位设置位true,及时线程内部的逻辑出现阻塞(sleep),也是可以用这个方法唤醒的。

正常来说,sleep会休眠到时间到,才能唤醒。此处给出的interrupt就可以使sleep内部触发一个异常,从而提前被唤醒。而我们自己设置的标志位无法实现这个效果。
例子

java 复制代码
在这里插入代码package thread;

public class Demo001 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            //Thread头部有一个现成的标志位,可以用来判定当前循环是否结束
            while(!Thread.currentThread().isInterrupted()){
                System.out.println("线程工作中");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

        });
        t.start();

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("让t终止");
        t.isInterrupted();
    }
}

运行结果

运行结果显示,异常确实是出现了,sleep确实唤被醒了,但是上述t仍然在继续工作!!并没真正结束!!!

interrupt()虽然唤醒线程了,此时sleep()方法会抛出异常,同时会自动清除刚才设置的标志位。这样就使得 设置标志位 这样的效果好像没生效一样。

为啥这么设定??

java这样设定是期望,当线程收到 要中断 这样的信号时候,它能够自由决定,接下来该怎么处理?

小例子:

有一天,我正在打游戏,我吗让我下楼买瓶酱油

当我收到这个信号,就有三种做法

1.直接丢下游戏,去买酱油

2.我把这局打完再去

3.直接忽略,假装没听见

同样的线程也可以采取这三种方式来执行

这样的目的是为了让线程有更多的 可操作空间。而这种可操作空间的前提是通过异常(异常可以清楚设置好的标志位,从而给了线程更多可操作的空间)。如果没有sleep(),没有抛出异常,就没有上述的可操作空间。

线程等待

join()方法是让一个线程等待另一个线程执行结束再继续执行,一般来说,等待操作都是要有一个超时时间的。本质上就是控制线程的执行顺序

t.join()的工作过程
(1)如果t线程正在运行,此时调用join的线程就会阻塞,一直阻塞到t线程执行结束为止
(2)如果t1线程已经执行结束了,此时调用join线程,就直接返回了,不会涉及到阻塞

public void join(long millis) 最多等 millis 毫秒,

public void join(long millis, int nanos) 同理,但可以更高精度

实际开发中一般不建议死等,最好要带有"超时时间"

获取当前线程引用

例子

java 复制代码
public class ThreadDemo {
    public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName());
   }
}

休眠当前线程

注意:因为线程的调度是不可控的,所以,这个方法只能保证实际休眠时间是大于等于参数设置的休眠时间的。 例如:sleep(1000),

系统会按照1000这个时间来控制让线程休眠 但是当1000时间到了之后,系统会唤醒这个线程.(阻塞->就绪)

但是不是说这个线程成了就绪状态,就能立即回到cpu上运行??(这中间有一个"调度"开销)

对于windows或者linux这样的系统来说,调度开销很大,可能达到ms级别.

有些场景,可能对于时间精度要求是很高的比如,发射卫星;或者导弹拦截 往往需要使用"实时操作系统",任务调度的开销在一定时间范围之内.

为了实时,也有很多的限制,功能上是不如windows和linux的.

观察线程的所有状态

线程的状态是一个枚举类型 Thread.State

java 复制代码
public class ThreadState {
    public static void main(String[] args) {
        for (Thread.State state : Thread.State.values()) {
            System.out.println(state);
       }
   }
}

线程状态和状态转移的意义

大家不要被这个状态转移图吓到,我们重点是要理解状态的意义以及各个状态的具体意思。

NEW:Thread对象已经有了.start方法还没调用

TERMINATED:Thread对象还在,内核中的线程已经没了.

RUNNABLE:就绪状态(线程已经在cpu上执行了/线程正在排队等待上cpu执行)

TIMED_WAITING:阻塞.由于sleep这种固定时间的方式产生的阻塞

WAITING:阻塞.由于wait这种不固定时间的方式产生的阻塞

BLOCKED:阻塞.由于锁竞争导致的阻塞

注意:

BLOCKED 表示等待获取锁, WAITING 和 TIMED_WAITING 表示等待其他线程发来通知.

TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒

相关推荐
除了菜一无所有!6 分钟前
基于SpringBoot技术的教务管理
java·spring boot·后端
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
开心工作室_kaic5 小时前
ssm010基于ssm的新能源汽车在线租赁管理系统(论文+源码)_kaic
java·前端·spring boot·后端·汽车
代码吐槽菌5 小时前
基于SSM的汽车客运站管理系统【附源码】
java·开发语言·数据库·spring boot·后端·汽车