线程的概论

线程实现

继承 Thread 类

public class MyThread extends Thread { 
 public void run() { 
 System.out.println("MyThread.run()"); 
 } 
}
MyThread myThread1 = new MyThread(); 
myThread1.start();

实现Runnable 接口创建线程

public class MyThread implements Runnable { 
 public void run() { 
    System.out.println("MyThread.run()"); 
 } 
 public static void main(String[] args) {
    new Thread(new MyThread()).start();
 }
}

实现 Callable 接口通过 FutureTask 包装器来创建 Thread 线程

public class CallableDemo implements Callable<String> {
    public static void main(String[] args) throws
            ExecutionException, InterruptedException {
        
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        Future<String> future = executorService.submit(new CallableDemo());
        System.out.println(future.get());
        executorService.shutdown();
    }

    @Override
    public String call() throws Exception {
        return "返回字符串类型";
    }
}

线程状态

线程一共有 6 种状态( new、runnable、blocked、waiting、time_waiting、terminated)

NEW

初始状态,线程被构建,但是还没有调用 start 方法

RUNNABLED

运行状态,JAVA 线程把操作系统中的就绪和运行两种状态统一称为“运行中”

BLOCKED

阻塞状态,表示线程进入等待状态,也就是线程,因为某种原因放弃了 CPU 使用权,阻塞也分为几种情况

  1. 等待阻塞:运行的线程执行 wait 方法,jvm 会把当前线程放入到等待队列
  2. 同步阻塞 :运行的线程在获取对象的同步锁时,若该同步锁被其他线程锁占用了,那么 jvm 会把当前的 线程放入到锁池中
  3. 其他阻塞:运行的线程执行 Thread.sleep 或者 t.join 方法,或者发出了 I/O 请求时,JVM 会把当前线程设置为阻塞状态,当 sleep 结束、join 线程终止、io 处理完毕则线程恢复

TIME_WAITING

超时等待状态,超时以后自动返回

TERMINATED

终止状态,表示当前线程执行完毕


在JDK 并发工具包中 常见 yield 让出CPU执行权限, lock锁中常用了TIME_WAITING 锁设置超时释放. 多线程竞争同一把锁下,竞争不到的线程调用park进入等待队列.

Mic提示:启动一个线程前,最好为这个线程设置线程名称,因为这样在使用 jstack 分析程序或者进行问题排查时,就会给开发人员提供一些提示
排查java线程状态: jps命令查询当前java中运行的线程的pid (jps命令工具JDK自带)
根据 获得的pid jstack #{pid} 查询堆栈信息

start()与run()区别

查看start方法源码, 方法中会调用 start0() 的本地方法来启动.
start0()方法又是Thread 的静态块中来注册的registerNatives方法.
registerNatives方法的定义的源码中如下
在这里插入图片描述
上图代码地址: http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/00cd9dc3c
2b5/src/share/native/java/lang/Thread.c
下面这个代码需要下载 hotspot源码
在这里插入图片描述
图中重要的是 new newJavaThread构造中做了什么
在这里插入图片描述
线程创建完成之后,开始调用线程启动方法 如下:
在这里插入图片描述

线程中断执行方式

官方推荐使用 interrupt 方法 进行中断,interrupt中是 其他线程调用此线程的interrupt 方法,改变了当前线程的某个字段状态标识, 此线程自己通过检查此值有没有发生变化来进行对应操作,可以通过isInterrupted()来判断是否被中断
举例:
第一种情况:
线程A创建开始运行,此时初始化 interrupt 中的标识为false,当B线程调用A线程interrupt 方法时,会改变成true,A线程在代码中自己编写(检查interrupt 状态)代码做相应逻辑处理.
第二种情况:
线程A创建开始运行,此时初始化 interrupt 中的标识为false,此时线程A开始睡眠,sleep操作, 同时B线程调用A线程interrupt 方法时,会抛出 InterruptedException
原因: B线程调用A线程interrupt 方法时,会修改状态值,并且唤醒睡眠中, 睡眠中的线程唤醒后发现睡眠时间还未到达,继续睡眠剩余设定时间,此时sleep方法中会进行is_interrupted()状态判断,判断是否睡眠途中有没有线程试图停止我,如果有 则抛出InterruptedException 异常进行响应.
注意: 阻塞线程唤醒后,如有其他线程通知过中断(true),也不会进行响应,继续干自己的事情,需要手动编写状态判断处理.

thread.interrupt() 方法

这个方法里面,调用了 interrupt0(),这个方法在前面分析start 方法的时候见过,是一个 native 方法,同样,我们找到 jvm.cpp 文件,找到JVM_Interrupt 的定义
在这里插入图片描述
接下来看看 Thread::interrupt(thr) 方法
在这里插入图片描述
Thread::interrupt 方法调用了 os::interrupt 方法,这个是调用平台的 interrupt 方法,这个方法的实现是在 os_*.cpp文件中,其中星号代表的是不同平台,因为 jvm 是跨平台的,所以对于不同的操作平台,线程的调度方式都是不一样的。我们以 os_linux.cpp 文件为例
在这里插入图片描述set_interrupted(true)实际上就是调用 osThread.hpp 中的set_interrupted()方法,在 osThread 中定义了一个成员属性 volatile jint _interrupted;

多个if判断为: 是否在睡眠,是否被park, 如正在睡眠或阻塞, 进行unpark唤醒或者重新抢锁,如果失败仍然可能被 park

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值