• 【Java并发编程二】线程的基本知识


    线程与进程的区别与联系

    进程:

     操作系统中最核心的概念就是进程,进程是对正在运行中的程序的一个抽象,是系统进行资源分配和调度的基本单位
     操作系统的其他所有内容都是围绕着进程展开的,负责执行这些任务的是CPU。
     进程一般由程序、数据集合和进程控制块三部分组成:程序用于描述进程要完成的功能,是控制进程执行的指令集。数据集合是程序在执行时所需要的数据和工作区。程序控制块,包含进程的描述信息和控制信息,是进程存在的唯一标志。

    线程:

     线程(thread)是操作系统能够进行运算调度的最小单位,其是进程中的一个执行任务(控制单元),负责当前进程中程序的执行。
     一个进程至少有一个线程,一个进程可以运行多个线程,这些线程共享同一块内存,线程之间可以共享对象、资源,如果有冲突或需要协同,还可以随时沟通以解决冲突或保持同步。

    区别

    • 本质区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位
    • 在开销方面:每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小
    • 所处环境:在操作系统中能同时运行多个进程(程序);而在同一个进程(程序)中有多个线程同时执行(通过CPU调度,在每个时间片中只有一个线程执行)
    • 内存分配方面:系统在运行的时候会为每个进程分配不同的内存空间;而对线程而言,除了CPU外,系统不会为线程分配内存(线程所使用的资源来自其所属进程的资源),线程组之间只能共享资源
    • 包含关系:没有线程的进程可以看做是单线程的,如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程

    线程的生命周期

     在Java的Thread线程类中,有一个枚举类,枚举了线程的各个状态:

    public enum State {
            // 线程还没有启动
            NEW,
    
            // 运行状态
            RUNNABLE,
    
            // 线程阻塞,无法获得想要获得的资源,可能是资源正在被锁定,或等待被解锁
            BLOCKED,
    
            // 由于调用其中一个线程,线程处于等待状态
            WAITING,
    
            // 具有指定等待时间的等待线程的线程状态
            TIMED_WAITING,
    
            // 终止线程的线程状态
            TERMINATED;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

     创建一个类继承Runnable接口,测试thread每个周期的状态:

    package myTest;
    
    public class myTest implements Runnable {
    
        public static void main(String[] args) throws InterruptedException {
            myTest test = new myTest();
            Thread thread = new Thread(test);
            System.out.println(thread.getState());
            thread.start();
            System.out.println(thread.getState());
            thread.sleep(1000);
            System.out.println(thread.getState());
    
        }
        public String sout() {
            return "test";
        }
        @Override
        public void run() {
            System.out.println(this.sout());
            // System.out.println("runnning");
        }
    }
    /**
    NEW
    RUNNABLE
    test
    TERMINATED
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    线程的切换

     CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。
     在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态。
     所以任务从保存到再加载的过程就是一次线程切换。

    并发的级别

    1. 阻塞
     一个线程是阻塞的,那么在其他线程释放资源之前,当前线程无法继续执行。阻塞可以分很多情况,一种是临时阻塞,就是当时要访问的资源暂时被锁住的了无法访问,所以就停留在此地,另一种是碰到了死锁,就会一直被阻塞,直到设计者发现它。

    2 无饥饿(Starvation-Free)
     如果线程之间是有优先级的,那么线程调度的时候总是会倾向于满足高优先级的线程。也就是说,对于同一个资源的分配,是不公平的。锁也分公平锁和非公平锁,对于非公平锁来说,系统允许高优先级的线程插队。这样就有可能导致低优先级的线程产生饥饿。但是如果是公平锁,满足先来后到,那么饥饿就不会产生,不管新来的线程优先级多高,要想获得资源,就必须乖乖排队。这样所有的线程都有机会执行。

    3 无障碍(Obstruction-Free)
     无障碍是一种最弱的非阻塞调度。无障碍表示两个线程可以畅通无阻的行动,但也会出现一些矛盾,比如一起访问同一个资源,又一起修改一个资源,那样就会出现数据的不可见性,对于无障碍的线程来说,一旦检测到这种情况,它就会立即对自己所做的修改进行回滚,确保数据安全。

    4 无锁(Lock-Free)
     无锁的并行都是无障碍的。但是这样会出现很多很多问题,比如说也是同时访问和修改资源,如果发生了资源的争夺,可能会陷入长时间的阻塞或者是直接奔溃,这对于程序来说,无疑是致命的。

    5 无等待(Wait-Free)
     无锁只要求一个线程可以在有限步数内完成操作,而无等待则是在无锁的基础上更进一步进行扩展,它要求所有的线程都必须在有限步数内完成,这样就不会引起线程饥饿问题。

  • 相关阅读:
    《统计学习方法》——第六章 逻辑斯谛回归与最大熵模型
    (二十) 共享模型之工具【JUC】【线程安全集合类】
    Perl5和Perl6对比使用Sigils的差别
    Java线程池基本原理
    【AI工具之Prezo如何自动生成PPT操作步骤】
    【博客438】Kubernetes IPAM分配IP原理
    VUE3与Uniapp 三 (属性绑定)
    Redis自动过期机制之key的过期监听
    百度集团副总裁吴甜解读跨模态大模型技术创新,发布AI作画神器文心·一格
    论文解读|清华&Meta提出HorNet,用递归门控卷积进行高阶空间相互作用
  • 原文地址:https://blog.csdn.net/qq_45722630/article/details/134484330