多线程(初阶)

文章目录

  • 一.初始线程(Thread)
    • 1.1.线程的概念
    • 1.2.线程的优势
      • 1.2.1.线程比进程更轻量
      • 1.2.2.并发编程
    • 1.3.线程和进程的区别
  • 二.Thread类方法
    • 2.1. java 中创建线程的方法
      • 2.1.1. 继承Thread,重写run
      • 2.1.2. 实现Ruuable接口
      • 2.1.3. 使用匿名内部类,继承Thread
      • 2.1.4.使用匿名内部类,实现Ruunable
      • 2.1.5.使用Lambda表达
    • 2.2.Thread 类及常见方法
      • 2.2.1. Thread的构造方法
      • 2.2.2.Thread的几个常见属性
        • 1.前/后台线程
        • 2.是否存活
        • 3.线程中断
      • 2.2.3.等待一个线程join
      • 2.2.4. 休眠当前线程
    • 2.3. 线程的状态
      • 2.3.1.java中线程的状态
      • 2.3.2.线程状态和转移

一.初始线程(Thread)

1.1.线程的概念

一个线程就是一个 “执行流”. 每个线程之间都可以按照顺序执行自己的代码. 多个线程之间 “同时” 执行着多份代码. 线程也可以理解成是在进程中独立运行的子任务.

比如,WeChat.exe运行时就有很多的子任务在同时运行。形如,好友视频线程、下载文件线程、传输数据线程等,这些不同的任务或者说功能都可以同时运行,其中每一项任务完全可以理解成是“线程”在工作,传文件、听音乐、发送图片表情等功能都有对应的线程在后台默默地运行.

1.2.线程的优势

1.2.1.线程比进程更轻量

 - 创建线程比创建进程更快
     
 - 销毁线程比销毁进程更快
   
 - 调度线程比调度进程更快

1.2.2.并发编程

如Windows系列,使用多任务操作系统Windows后,可以最大限度地利用CPU的空闲时间来处理其他的任务,比如一边让操作系统处理正在由打印机打印的数据,一边使用Word编辑文档.所以使用多线程技术后,可以在同一时间内运行更多不同种类的任务.

并行 微观上,同一时刻,两个核心上的进程,是同时执行的
并发 微观上,同一个时刻,一个核心上只能运行一个进程,但是它能够快速的进程切换(宏观让人感知不到).
这些都是内核负责处理的,应用程序感知不到,因此往往把并行和并发,统称为并发

单任务和多任务的模型图
多线程(初阶)_第1张图片

在多任务中,CPU可以在任务1和任务2之间来回切换,使任务2不必等5秒后执行,运行效率提升

1.3.线程和进程的区别

  • 进程是包含线程的. 每个进程至少有一个线程存在,即主线程.
  • 进程和进程之间不共享内存空间. 同一个进程的线程之间共享同一个内存空间(主要指的是内存和文件描述符表).

进程是系统分配资源的最小单位,线程是系统调度的基本单位(如果每个进程有多个线程,每个线程是独立在CPU调度的)

一个线程是通过一个PCB来描述的,所以一个进程里面可能对应一个PCB,也可能是对应多个.
PCB里的状态,上下文,优先级,记账信息,都是每个线程自己的,各自记录各自的,但是同一个进程的PCB之间,pid是一样的,内存指针和文件描述表也是一样的.

线程模型,天然就是资源共享的,多线程争抢同一个资源(同一个变量)非常容易触发竞争
而进程模型,天然就是资源隔离的,不容易触发,进行进程间的通信的时候,多个进程访问同一个资源,可能出现问题
线程是操作系统中的概念. 操作系统内核实现了线程这样的机制, 并且对用户层提供了一些 API 供用户使,而Java 标准库中 Thread 类可以视为是对操作系统提供的 API 进行了进一步的抽象和封装.

二.Thread类方法

先来介绍start,就是调用操作系统的API,通过操作系统内核创建线程的PCB,并且把要执行的指令加给PCB,当PCB被调度到CPU上执行的时候,也就执行到了线程run方法中的代码

Thread  t = new MyThread();
t.start();

start是创建了个线程,由新的线程来执行run方法

2.1. java 中创建线程的方法

2.1.1. 继承Thread,重写run

多线程(初阶)_第2张图片

2.1.2. 实现Ruuable接口

多线程(初阶)_第3张图片

2.1.3. 使用匿名内部类,继承Thread

多线程(初阶)_第4张图片

2.1.4.使用匿名内部类,实现Ruunable

多线程(初阶)_第5张图片

2.1.5.使用Lambda表达

多线程(初阶)_第6张图片

2.2.Thread 类及常见方法

2.2.1. Thread的构造方法

方法 说明
Thread() 创建线程对象
Thread(Runnable target) 使用 Runnable 对象创建线程对象
Thread(String name) 创建线程对象,并命名
Thread(Runnable target, String name) 使用 Runnable 对象创建线程对象,并命名
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("名字");
Thread t4 = new Thread(new MyRunnable(), "名字");

2.2.2.Thread的几个常见属性

多线程(初阶)_第7张图片

  • ID 是线程的唯一标识,不同线程不会重复
  • 名称是各种调试工具用到
  • 优先级高的线程理论上来说更容易被调度到
  • 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
  • 是否存活,即简单的理解,为 run 方法是否运行结束了

1.前/后台线程

前台线程,会阻止进程结束,前台线程的工作没完成,进程是结束不了的
后台线程,不会阻止进程结束,后台线程工作没完成,进程也是可以结束的
手动创建的线程,默认都是前台的,包括main默认也是前台的其他的jvm自带的线程都是后台线程
也可以手动的使用setDeamon设置成后台线程(守护线程)

2.是否存活

多线程(初阶)_第8张图片
在调用是start之前,调用isAlive()是false,调用start之后,isAlive就是true,如果内核里线程把run运行完了,此时线程销毁,pcb随之释放,但是Thread t这个对象不一定被释放,此时isAlive是false

public class Thread5 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()->{
            while (true){
                System.out.println("Hellp Thread !");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        System.out.println(t.isAlive());
        t.start();
        while (true){
            Thread.sleep(1000);
            System.out.println(t.isAlive());

        }
    }
}

t的run还没跑,isAlive就是false
t的run还在跑,isAlive就是true
t的run跑完l,isAlivejiusfalse

3.线程中断

中断的意思是,不是让线程立即终止,而是通知,应该要停止,是否真的停止,取决于线程具体的代码写法

  1. 使用标志位来控制位线程是否要停止

  2. 使用Thread自带的标志位,来进行判断

方法 说明
public void interrupt() 中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置标志位
public static boolean interrupted() 判断当前线程的中断标志位是否设置,调用后清除标志位
public boolean isInterrupted() 判断对象关联的线程的标志位是否设置,调用后不清除标志位

多线程(初阶)_第9张图片
intterrupt做两件事
1.把线程内部的标志位(boolean)给设置成true
2.如果线程在进行sleep,就会触发异常,把sleep唤醒,但是sleep在唤醒的时候,会把刚才设置的这个标志,在设置回false
多线程(初阶)_第10张图片
如果线程因为调用 wait/join/sleep 等方法而阻塞挂起,则以 InterruptedException 异常的形式通
知,清除中断标志
当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择
忽略这个异常, 也可以跳出循环结束线程.
如下列图片
多线程(初阶)_第11张图片多线程(初阶)_第12张图片
多线程(初阶)_第13张图片

2.2.3.等待一个线程join

线程是一个随机调度的过程,等待线程,就是控制两个线程的结束顺序

方法 说明
public void join() 等待线程结束
public void join(long millis) 等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos) 同理,但可以更高精度

多线程(初阶)_第14张图片
当开始执行的时候,他已经结束,此时join不会阻塞,就会立即返回

2.2.4. 休眠当前线程

让线程休眠,本质上就是让这个线程不参与调度

方法 说明
public static void sleep(long millis) throws InterruptedException 休眠当前线程 millis毫秒
public static void sleep(long millis, int nanos) throws InterruptedException 可以更高精度的休眠

多线程(初阶)_第15张图片

一旦线程进入阻塞状态,对应PCB就进入阻塞队列,此时就暂时无法参与调度

PCB是使用链表来组织的(并不具体)实际的情况并不是一个简单的链表,这是一系列以链表为核心的数据结构

2.3. 线程的状态

状态是针对当前的线程调度的情况来描述的,线程是调度的基本单位,状态是线程的属性

2.3.1.java中线程的状态

在java对于线程的状态,进行细化
多线程(初阶)_第16张图片
线程的状态是一个枚举类型Thread.State

public static void main(String[] args) {
        for (Thread.State state: Thread.State.values()) {
            System.out.println(state);
        }
  }

多线程(初阶)_第17张图片

  • NEW: 安排了工作, 还未开始行动
  • RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.
  • BLOCKED:这几个都表示排队等着其他事情
  • WAITING: 这几个都表示排队等着其他事情
  • TIMED_WAITING: 这几个都表示排队等着其他事情
  • TERMINATED: 工作完成了.

2.3.2.线程状态和转移

先简单了解一下
多线程(初阶)_第18张图片

你可能感兴趣的:(JavaEE,java,开发语言)