• 【JavaEE】进程与线程的创建


    目录

    一、进程

    1、概念

    2、描述与组织

    1.PCB

    2.PCB的成员变量

    3.组织

    3、虚拟地址空间

    4、进程间的通信  

    5、进程创建与销毁 

    1.进程的创建 

    2,进程的销毁

    二、线程

    1、概念

    2、为什么要有线程

    3、进程与线程的关系

    1、一个进程必须有一个线程叫主线程,也可以有多个线程

    2、进程与进程之间不能共享内存空间,而线程之间可以共享内存资源

    3、线程是轻量级的进程

    4、进程是系统分配资源的基本单位,线程是系统调度的基本单位

    4、线程的创建销毁

    5、线程的效率

    三、Java里线程的创建

    1、方法1:继承Thread类

    2、方法2:实现Runnable接口

     3、方法3:匿名内部类创建Thread的子类

    4、方法4:匿名内部类实现Runnable接口

    5、lambda表达式

    四、串行与线程代码的效率


    一、进程

    1、概念

    进程是操作系统对一个正在运行的程序的一种抽象,可以把进程看作程序的一次运行,是操作系统进行资源分配的基本单位

    2、描述与组织

    1.PCB

    是一个用于描述进程的结构体,一个进程可以有一个PCB也可以有多个

    2.PCB的成员变量

    1.pid:进程的身份标识,同一个主机同一时刻进程的pid是唯一的     

    2.内存指针:用于描述进程持有的内存资源,一个可执行程序运行后,操作系统会把核心资源加载到内存里

    3.文件描述符表:用于描述一个进程持有的文件资源,用于记录进程打开的文件

    4.进程状态:用于描述一个进程能不能被调度到CPU执行,有两种状态,一种是就绪状态,可以被调度到CPU执行,还有一种是堵塞状态,不可以被调度到CPU执行

    5.进程优先级:描述进程执行的优先关系

    6.进程上下文:一个进程在CPU执行了一会后,切换到别的进程,就需要保存存档,下次执行该进程时,就恢复原来继续往下执行

    7.进程记账信息:记录一个进程执行的时间

    3.组织

    每个PCB是通过双向链表来组织的

    3、虚拟地址空间

    给每个进程分配的内存资源,叫虚拟地址空间,不是真实的物理地址,通过专门的设备MMU来检测进程是否访问越界,后访问物理地址,使用虚拟地址空间相当于增加了进程之间的隔离性,一个进程不能访问另一个进程的内存空间

    4、进程间的通信  

    有了虚拟地址空间增加了隔离性但也有了新的问题---进程之间的交互,进程之间的交互就设计到进程间的通信,进程之间的通信,是通过一个多个进程都能访问到的公共资源比如,一块内存,一个网卡等

    5、进程创建与销毁 

    1.进程的创建 

    创建PCB-》分配资源-》插入链表

    2,进程的销毁

    从链表删除 -》释放持有的资源-》销毁PCB

    二、线程

    1、概念

    一个线程就是一个人执行流,每个线程都可以按照顺序执行自己的代码,多个线程同时执行多个代码

    2、为什么要有线程

    并发编程的刚需,当需要多个进程时,进程的创建与销毁操作效率比较低,而多个线程创建与销毁,相比比较高效

    3、进程与线程的关系

    1、一个进程必须有一个线程叫主线程,也可以有多个线程

    2、进程与进程之间不能共享内存空间,而线程之间可以共享内存资源

    3、线程是轻量级的进程

    4、进程是系统分配资源的基本单位,线程是系统调度的基本单位

    每一个线程都是一个执行流,都可以在CPU进行调度,如果把进程比作工厂,线程就相当于是工厂里的流水线

    4、线程的创建销毁

    创建第一个线程时系统分配资源,后续创建线程不需要申请资源,线程销毁时也只是销毁到最后一个线程才释放资源,一个PCB 也就是一个线程

    5、线程的效率

    在一定程度上线程使用,是高效的,而并不是越多越好,CPU的核心数是有限的,如果线程的数量超出一定范围反而会降低效率

    三、Java里线程的创建

    在操作系统里面原生的线程API是C语言的,在Java里将其封装为Java风格的API

    1、方法1:继承Thread类

    让一个类继承Thread然后重写run方法

    run方法里面就是这个线程要做的事,run方法就是线程的入口方法

    1. class MyThread extends Thread{
    2. @Override
    3. public void run() {
    4. while(true){
    5. System.out.println("这个线程要执行的逻辑");
    6. try {
    7. Thread.sleep(1000);
    8. } catch (InterruptedException e) {
    9. e.printStackTrace();
    10. }
    11. }
    12. }
    13. }
    14. public class demo1 {
    15. public static void main(String[] args) {
    16. MyThread myThread = new MyThread();
    17. myThread.start();
    18. }
    19. }

    使用这个类实例化一个对象并不是创建了线程,而通过对象调用了父类里的start方法才是创建了一个线程,main方法执行的逻辑是主线程,main就是主线程的入库口方法,线程是并发执行的,也就是run里面的代码与main函数里面的代码是同时执行的

    2、方法2:实现Runnable接口

    实现接口后重写run方法,实例一个该类的对象,然后实例化一个Thread的对象,在构造函数传入实例化的实现Runnable接口的类的对象,通过Thread对象调用start方法就创建了一个线程,这种创建方法将创建线程与线程所执行的逻辑分开,实现了代码的解耦合

    1. class MyRunnable implements Runnable{
    2. @Override
    3. public void run() {
    4. System.out.println("这是这个线程要执行的逻辑");
    5. }
    6. }
    7. public class demo2 {
    8. public static void main(String[] args) {
    9. MyRunnable myRunnable = new MyRunnable();
    10. Thread thread = new Thread(myRunnable);
    11. thread.start();
    12. }
    13. }

     3、方法3:匿名内部类创建Thread的子类

    1. public class demo3 {
    2. public static void main(String[] args) {
    3. Thread thread = new Thread(){
    4. @Override
    5. public void run() {
    6. System.out.println("线程执行的逻辑");
    7. }
    8. };
    9. thread.start();
    10. }
    11. }

    4、方法4:匿名内部类实现Runnable接口

    1. public class demo4 {
    2. public static void main(String[] args) {
    3. Thread thread = new Thread(new Runnable() {
    4. @Override
    5. public void run() {
    6. System.out.println("线程执行的逻辑");
    7. }
    8. });
    9. }
    10. }

    5、lambda表达式

    1. public class demo4 {
    2. public static void main(String[] args) {
    3. Thread thread = new Thread(()->{
    4. System.out.println("线程执行的逻辑");
    5. });
    6. }
    7. }

    四、串行与线程代码的效率

    让a自增到一个值重复两次自增,通过执行时间来判断两种方式的效率

    1. public class demo4 {
    2. public static final long NUM = 10_0000_0000L;
    3. public static void main(String[] args) {
    4. func1();
    5. func2();
    6. }
    7. //串行代码
    8. public static void func1(){
    9. long begin = System.currentTimeMillis();
    10. long a = 0L;
    11. for (int i = 0; i < NUM; i++) {
    12. a++;
    13. }
    14. a = 0;
    15. for (int i = 0; i < NUM; i++) {
    16. a++;
    17. }
    18. long end = System.currentTimeMillis();
    19. System.out.println("串行代码执行时间"+(end-begin)+"ms");
    20. }
    21. //线程代码
    22. public static void func2(){
    23. long begin = System.currentTimeMillis();
    24. Thread thread1 = new Thread(()->{
    25. long a = 0L;
    26. for (int i = 0; i < NUM; i++) {
    27. a++;
    28. }
    29. });
    30. Thread thread2 = new Thread(()->{
    31. long a = 0L;
    32. for (int i = 0; i < NUM; i++) {
    33. a++;
    34. }
    35. });
    36. thread1.start();
    37. thread2.start();
    38. //让线程执行完毕
    39. try {
    40. thread1.join();
    41. thread2.join();
    42. } catch (InterruptedException e) {
    43. e.printStackTrace();
    44. }
    45. long end = System.currentTimeMillis();
    46. System.out.println("线程代码执行时间"+(end-begin)+"ms");
    47. }
    48. }

     

     

  • 相关阅读:
    分布式事务使用GlobalTransactional注解insert 报错java.sql.SQLException: 调用中的无效参数,
    管理信息系统总复习、第五章(企业应用系统和业务流程集成)
    docker镜像导出保存为tar和tar包导入成docker镜像
    redis在服务器linux下的启动的相关命令(安装和配置)
    BIOS 中断服务 设置颜色
    迭代加深算法题目
    PyOpenGL笔记
    john 探测(爆破)弱口令(包含linux机器,aix小机)亲测可用
    Vue 快速入门之第四章 路由
    Java实现手动操作定时任务功能的简单例子(动态创建定时任务)
  • 原文地址:https://blog.csdn.net/qq_61903414/article/details/126679007