多线程基础知识

快速认识线程

线程是程序执行的一个路径,每个线程都有自己的局部变量表,程序计数器(指向正在执行的指令指针)以及各自的生命周期。
在这里插入图片描述
其实Thread的run和start就是一个比较典型的模板设计模式,父类编写算法结构代码,子类实现逻辑细节。这样做的好处是,程序结构由父类控制,并且是final修饰的,不允许重写,子类只需要实现想要的逻辑任务即可。

实现线程的执行单元有两种方式,第一种是重写Thread的run方法,第二种是实现Runnable接口的run方法,并将Runnable实例用作构造Thread的参数。



深入理解Thread构造函数

JVM内存结构

JVM在执行Java程序的时候会把对应的物理内存划分为不同的内存区域,每一个区域都存放着不同的数据,也有不同的创建与销毁时机,有些分区会在JVM启动的时候就创建,有些则是在运行时才创建,比如虚拟机栈。
在这里插入图片描述

1,程序计数器

程序计数器在JVM中所起的作用就是用于存放当前线程接下来将要执行的字节码指令,分支,循环,跳转,异常处理等信息。在任何时候,一个处理器只执行其中一个线程中的指令,为了能够在CPU时间片轮转切换上下文后顺利回到正确的执行位置,每个线程都都需要具有一个独立的程序计数器,各个线程之间互相不影响,因此JVM将此块内存区域设计成了线程私有的。

2,Java虚拟机栈

Java虚拟机栈也是线程私有的,它的生命周期与线程相同,是在JVM运行时所创建的,在线程中,方法在执行的时候都会创建一个名为栈帧的数据结构,主要用于存放局部变量表,操作栈,动态链接,方法出口等信息,方法的调用对应着栈帧在虚拟机栈中的压栈和弹栈过程。
每一个线程在创建的时候,JVM都会为其创建对应的虚拟机栈,虚拟机栈的大小可以通过-xss来配置,方法的调用是栈帧被压入和弹出的过程。
在这里插入图片描述

3,本地方法栈

Java中提供了调用本地方法的接口,也就是C/C++程序,在线程的执行过程中,经常会碰到调用JNI的方法的情况,比如网络通信情况,文件底层的操作,甚至是String的intern等都是JNI方法,JVM为本地方法所划分的内存区域便是本地方法栈,这块内存区域其自由度非常高,完全靠不同的JVM厂商来实现,Java虚拟机规范并未给出强制的规定,同样它也是线程私有的内存区域。

4,堆内存

堆内存是JVM中最大的一块内存区域,被所有的线程所共享,Java在运行期间创建的所有对象几乎都存放在该内存区域,该内存区域也是垃圾回收器重点照顾的区域,因此有些时候堆内存被称为"GC堆"。堆内存一般被细分为新生代和老年代。

5,方法区

方法区也是被多个线程所共享的内存区域,它主要用于存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,虽然在Java虚拟机规范中,将方法区划分为堆内存的一个逻辑分区,但它还是经常被称为"非堆",有时候也被称为"持久代"。在HotSpot JVM中,方法区还会被细分为持久代和代码缓存区。

6,Java8元空间

自JDK1.8版本起,JVM的内存区域发生了一些改变,实际上是持久代内存被彻底删除,取而代之的是元空间。程序计数器是比较小的一块内存,而且这部分内存是不会出现任何溢出异常的,与线程创建,运行,销毁等关系比较大的是虚拟机栈内存了,而且栈内存划分的大小将直接决定在一个JVM进程中可以创建多少个线程。



Thread API的详细介绍

yield方法介绍

yield方法属于一种启发式的方法,其会提醒调度器我愿意放弃当前的CPU资源,如果CPU的资源不紧张,则会忽略这种提醒。调用yield方法会使当前线程从RUNNING状态切换到RUNNABLE状态。

不要企图在程序设计当中企图使用线程优先级绑定某些特定的业务,或者让业务严重依赖于线程优先级,这可能让你大失所望。线程的优先级不能小于1也不能大于10,如果指定的线程优先级大于线程所在group的优先级,那么指定的优先级就会失效,取而代之的是group的最大优先级。线程默认的优先级和它的父类保持一致,一般情况下都是5,因为main线程的优先级就是5,所以它派生出来的线程都是5。
线程interrupt下列方法的调用会使得当前线程进入阻塞状态,而调用当前线程的interupt方法,就可以打断阻塞。

  • Object的wait方法
  • Thread的sleep方法
  • Thread的join方法

一旦线程在阻塞的情况下被打断,都会抛出一个称为InterruptedException的异常,这个异常就像是一个signal一样通知当前线程被打断了。
isInterrupted是Thread的一个成员方法,它主要判断当前线程是否被中断,该方法仅仅是对interrupt标识的一个判断,并不会影响标识发生任何变化。
interupted是一个静态方法,虽然其也用于判断当前线程是否中断,但是它和成员方法isInterrupted还是有很大的区别的,调用该方法会直接擦除线程的interupt标识。如果当前线程被打断了,那么第一次调用interrupted方法会返回true,并且立即擦除了interrupt标识;第二次包括以后的调用都会返回false,除非在此期间线程又一次地被打断。

线程join

与sleep一样它也是一个可中断的方法,也就是说,如果有其他线程执行了对当前线程的interrupt操作,它也会捕获到中断信号,并且擦除线程的interrupt标识。

线程join方法详解

join某个线程A,会使当前线程B进入等待,直到线程A结束生命周期,或者到达给定的时间,那么在此期间B线程是处于BLOCKED的,而不是A线程。

关闭一个线程
  1. 线程结束生命周期正常结束
  2. 捕获中断信号关闭线程
  3. 使用volatile开关控制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值