线程与进程基础

文章目录

  • 前言
  • [一、 线程与进程](#一、 线程与进程)
    • [1.1 什么是线程与进程?](#1.1 什么是线程与进程?)
    • [1.2 并发与并行](#1.2 并发与并行)
    • [1.3 同步调用与异步调用](#1.3 同步调用与异步调用)
    • [1.4 为什么要使用多线程?](#1.4 为什么要使用多线程?)

前言


在学习juc前,需要先对进程和线程之间整体有一个认知。我们之前或多或少接触过,一些特别高大上的概念,比如多线程,高并发 之类的。该文就是先对这些概念整体理清,为后续学习扫清障碍。


一、 线程与进程

1.1 什么是线程与进程?

进程

  • 进程是用来存放数据与指令等运行程序的组成部分,然后指令运行的时候还需用到磁盘、IO设备,网络等,其中进程就是用来加载指令,管理内存·,管理IO的。

  • 程序运行的时候,从磁盘 -> 内存就代表一个进程开启了

  • 进程可以看作一个程序的示例,比如我们打开任务管理器:

这表明,对于应用来说,可以运行一个或者多个进程。

线程

  • 一个进程包括多个线程
  • 一个线程就是一个指令流,将指令流的一条条指令以一定顺序交给CPU执行
  • Java中,线程是最小的调度单位,进程作为资源分配的最小单位。windows中,进程不活动,只是作为线程的容器。

二者对比 :

  • 进程拥有共享的资源,比如内存空间的,供子集线程共享
  • 进程间的通信较为复杂
    • 同一台计算机的进程通信称为IPC,比如套接字、消息队列等。
    • 不同计算机的通信要通过网路,并遵守共同的协议,比如http等。
  • 线程通信比较简单,因为它们可以共享进程内的内存,一个例子是多个线程访问一个共享变量。
  • 线程更轻量级,上下文切换成本较低。

1.2 并发与并行


  • 并发:两个及两个以上的任务在同一时间段执行
  • 并行:两个及两个以上的任务在同一时刻执行

并发

​ 在单核cpu中,线程实际是串行执行 的。操作系统中的组件,叫做任务调度器,将cpu的时间片(windows下接近15ms)分给不同的线程使用,只是由于cpu在线程间的切换非常快,导致体感上是同时运行的

​ 总结一句话:微观串行,宏观并行,但是,实际上还是串行。

并行

​ 在多核cpu中,每个核心可以处理一个线程,这样就可以真正意义上实现并行,即同一时刻,同时运行多个线程。

如图:

1.3 同步调用与异步调用

注意

代码中的Constants.MP4_FULL_PATH就理解为一个文件即可。

该代码作用就是花时间读取一个文件。

  • 同步调用
  • 异步调用

从运行结果,可以看出来,异步调用是通过一个Thread-0的线程执行的。

从上面的运行结果可以得到两者的含义。


同步调用:发出一个调用之后,结果没有返回的话,该调用就不可以返回,一直等待。

异步调用:调用在发出后,不用等待返回结果,调用直接返回。


其实简单来说:
异步调用 就是在main线程里面新开一个线程,并且新开的线程执行与否对于主线程接下来往下执行没有影响。
同步调用就是一直只执行当前线程呗,不开其它的线程。

根据这个,我们就可以引出下面的多线程:

  • 多线程的作用

​ 多线程可以让方法执行变成异步的(即不要干等着)。比如读取磁盘文件时,需要5秒,那如果我们不使用多线程,这5秒什么都做不了只能干等着。

1.4 为什么要使用多线程?

  • 在单核时代,使用多线程可以提高cpu和io系统的运行效率,如果只运行了一个java进程的情况下,当线程进行读取io的操作,此时线程被阻塞。如果没有多线程,那么此时整个进程都被阻塞, 无法使用cpu,系统整体效率只有50%。但是如果使用多线程的话,一个线程阻塞,其它线程还可以继续访问,大大提高系统运行效率。但是需要理解的是,单核中,多线程并不起到减少时间的作用。(单核只作了解)

  • 在多核时代。多线程主要是为了提高进程利用多核cpu的能力。

eg : 处理一个复杂的任务,如果只有一个线程,那么只有一个核心被利用到。失去了多核的作用,但是多个线程就可以同时使用多个核心同时处理任务,提高了解决任务的效率,时间约等于(单核时执行的时间 / cpu核心数)。

实例:

java 复制代码
@Benchmark
public int c() throws Exception {
    int[] array = ARRAY;
    FutureTask<Integer> t1 = new FutureTask<>(()->{
        int sum = 0;
        for(int i = 0; i < 250_000_00;i++) {
            sum += array[0+i];
        }
        return sum;
    });
    FutureTask<Integer> t2 = new FutureTask<>(()->{
        int sum = 0;
        for(int i = 0; i < 250_000_00;i++) {
            sum += array[250_000_00+i];
        }
        return sum;
    });
    FutureTask<Integer> t3 = new FutureTask<>(()->{
        int sum = 0;
        for(int i = 0; i < 250_000_00;i++) {
            sum += array[500_000_00+i];
        }
        return sum;
    });
    FutureTask<Integer> t4 = new FutureTask<>(()->{
        int sum = 0;
        for(int i = 0; i < 250_000_00;i++) {
            sum += array[750_000_00+i];
        }
        return sum;
    });
    new Thread(t1).start();
    new Thread(t2).start();
    new Thread(t3).start();
    new Thread(t4).start();
    return t1.get() + t2.get() + t3.get()+ t4.get();
}
@Benchmark
public int d() throws Exception {
    int[] array = ARRAY;
    FutureTask<Integer> t1 = new FutureTask<>(()->{
        int sum = 0;
        for(int i = 0; i < 1000_000_00;i++) {
            sum += array[0+i];
        }
        return sum;
    });
    new Thread(t1).start();
    return t1.get();
}

运行结果:

上述代码含义就是 :

4个线程(t1、t2、t3、t4),每个线程调用方法执行2500万次,打印信息中是c开头的。

d开头方法是一个方法调用1亿次。

c为异步调用,d为同步调用,从结果来看,c方法的效率显著高于d方法(Score越小,效率越高)。

但是如果是在单核cpu中的话,不会出现性能的提升,因为单核的本质上还是串行,并不会产生并行的效果。

相关推荐
懒鸟一枚3 分钟前
详解Maven的setting配置文件中mirror和repository的区别
java·maven
QQ_538876917 分钟前
Z240004基于Java+ssm+maven+mysql的房屋租赁系统的设计与实现
java·mysql·spring·maven
shaoweijava13 分钟前
私人诊所管理系统(源码+数据库+报告)
java·开发语言·数据库·spring boot·mysql·mybatis
知识分享小能手14 分钟前
Java学习教程,从入门到精通,Java Stack(堆栈)语法知识点及语法知识点(58)
java·大数据·开发语言·学习·intellij-idea·java后端·java开发
瑞金彭于晏25 分钟前
yml和xml分别代表什么
xml·java·mybatis
YAy1739 分钟前
FastJson反序列化学习-01
java·开发语言·安全·web安全·网络安全
MatthewMao1 小时前
设计模式11:单例模式(全局唯一)
java·单例模式·设计模式
123yhy传奇1 小时前
【学习总结|DAY018】Java异常、泛型、集合框架
java·开发语言
Java学长-kirito1 小时前
springboot/ssm武理多媒体信息共享平台Java代码编写web项目视频作品分享源码
java·spring boot·后端
.生产的驴1 小时前
Docker Compose 缓存Redis主从节点的搭建 分布式搭建
java·redis·分布式·nginx·缓存·docker·容器