并发基本概念

并发基本概念

 

进程与线程

进程

  • 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存,在指令运行过程中还需要用到磁盘,网络等设备,进程就是用来加载指令,管理内存,管理IO的
  • 当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程
  • 进程就可以视为程序的一个实例,大部分程序可以同时运行多个实例进程(;例如记事本,画图,浏览器等),也有的程序只能启动一个实例进程(例如网易云音乐,360安全卫士)

线程

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

进程与线程的区别

  • 进程基本上相互独立的,而线程存在于进程内,是进程的一个子集
  • 进程拥有共享的资源,如内存空间等,供其内部的线程共享
  • 进程间通信较为复杂
    • 同一台计算机的进程通信称为 IPC(Inter-process communication)
    • 不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,例如 HTTP
  • 线程通信相对简单,因为它们共享进程内的内存,一个例子是多个线程可以访问同一个共享变量
  • 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低

并行与并发

并发

单核 cpu 下,线程实际还是串行执行的。操作系统中有一个组件叫做任务调度器,将cpu的时间片(windows下时间片最小约为 15 毫秒)分给不同的程序使用,只是由于 cpu 在线程间(时间片很短)的切换非常快,人类感觉是 同时运行的 。总结为一句话就是: 微观串行,宏观并行 , 一般会将这种 线程轮流使用 CPU 的做法称为并发, concurrent

并行

多核cpu下.每个核(core)都可以调度运行线程,这时候线程可以是并行的
notion image
notion image
 

并行的级别

  • 阻塞
    • 指当一个线程进入临界区后,其他线程必须等待
  • 非阻塞
    • 无障碍(Obstruction-Free)
        1. 无障碍是一种最弱的非阻塞调度
        1. 线程可以自由进入临界区
        1. 进入临界区后,在无竞争时,有限步内完成对临界区资源的操作
        1. 有竞争时,回滚数据,放弃对临界区资源的操作
    • 无锁(Lock-Free)
        1. 首先它是无障碍的
        1. 其次它保证所有进入临界区的线程有一个可以胜出
    • 无等待(Wait-Free)
        1. 无锁的
        1. 要求所有的线程都必须在有限步内完成
        1. 无饥饿的

并行与并发区别

  • 并行:指两个或多个事件在同一时刻发生(同时发生)。(双车道同时开过两辆车)
  • 并发:指两个或多个事件在同一个时间段内发生。(单车道,先后开过两辆车)
 

查看进程线程的方法

windows

  • 任务管理器可以查看进程和线程数,也可以杀死进程
  • tasklist 查看进程
  • taskkill 杀死进程

linux

  • ps -fe 查看所有进程
  • ps -fT -p <PID>查看某个进程的所有线程
  • kill -9 杀死进程
  • top按大写H切换是否显示线程
  • top -H -p <PID> 查看某个进程的所有线程

java

  • jps命令查看所有java进程
  • jstack <PID> 查看某个Java进程的所有线程状态
  • jconsole 查看某个进程中线程的运行情况(图形界面)
jconsole远程监控配置
需要以如下方式运行你的 java 类
java -Djava.rmi.server.hostname=`ip地址` -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=`连接端口` -Dcom.sun.management.jmxremote.ssl=是否安全连接 -Dcom.sun.management.jmxremote.authenticate=是否认证 java类
notion image
修改 /etc/hosts 文件将 127.0.0.1 映射至主机名,映射至主机名如果要认证访问,还需要做如下步骤
  • 复制 jmxremote.password 文件
  • 修改 jmxremote.password jmxremote.access 文件的权限为 600 即文件所有者可读写
  • 连接时填入 controlRole(用户名),R&D(密码)

用户线程与守护线程

在Java中有两类线程:User Thread(用户线程或非守护线程)、Daemon Thread(守护线程) ,
只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作
Daemon的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。
User和Daemon两者几乎没有区别,唯一的不同之处就在于虚拟机的离开:如果 User Thread已经全部退出运行了,只剩下Daemon Thread存在了,虚拟机也就退出了。
因为没有了被守护者,Daemon也就没有工作可做了,也就没有继续运行程序的必要了。
@Slf4j(topic = "c.Test15") public class Test15 { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(() -> { while (true) { if (Thread.currentThread().isInterrupted()) { break; } } log.debug("结束"); }, "t1"); //将t1设为守护线程 t1.setDaemon(true); t1.start(); Thread.sleep(1000); log.debug("结束"); } } //output //21:51:45.706 c.Test15 [main] - 结束
Tomcat中的AcceptorPoller线程都是守护线程,所以Tomcat接收到shutdown命令后,不会等待它们处理完当前请求
守护线程并非只有虚拟机内部提供,用户在编写程序时也可以自己设置守护线程:
Thread daemonTread = new Thread(); // 设定 daemonThread 为 守护线程,default false(非守护线程) daemonThread.setDaemon(true); // 验证当前线程是否为守护线程,返回 true 则为守护线程 daemonThread.isDaemon();
这里有几点需要注意:
  1. thread.setDaemon(true)必须在thread.start()之前设置,否则会抛出一个IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。
  1. Daemon线程中产生的新线程也是Daemon的。
  1. 不要认为所有的应用都可以分配给Daemon来进行服务,比如读写操作或者计算逻辑。

同步和异步

同步,可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。
异步,执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。
同步如打电话,通信双方不能断(我们是同时进行,同步),你一句我一句,这样的好处是,对方想表达的信息我马上能收到,但是,我在打着电话,我无法做别的事情。
异步如收发收短信,对比打电话,打电话我一定要在电话的旁边听着,保证双方都在线,而收发短信,对方不用保证此刻我一定在手机旁,同时,我也不用时刻留意手机有没有来短信。这样的话,我看着视频,然后来了短信,我就处理短信(也可以不处理),接着再看视频。
notion image