1、什么是进程与线程
(1)进程
:是程序的一次执行过程,是系统运行程序的基本单位;系统的一个进程就是程序从创建、运行到消亡的过程。进程有自己独立的一块内存空间(虚空间)
在Java
中,当我们启动一个main
函数其实就是启动了一个JVM
进程,main
函数所在的线程就是这个进程的一个线程,也叫主线程。更直观的就是,打开电脑的任务管理器,就可以看到当前Windows
的运行进程。
(2)线程
:线程和进程相似,但是线程是比进程更小的一个执行单位,一个进程在执行过程中可以产生多个线程。
与进程不同的是,多个线程共享进程的堆
和方法区
资源,但是每个线程有自己的程序计数器、虚拟机栈和本地方法区
(存在cpu
缓存中)。
所以系统在产生一个线程,或者在多个线程之间切换工作时,负担比进程小,所以线程也被成为轻量级进程
。
2、进程与线程的区别
从JVM
来看,一个进程可以有多个线程,多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法区
。如下图:
线程是进程划分的更小的执行单位,两者最大的不同在于各进程是独立的,但是各个线程不一定,同一个进程中的多个线程可能会相互影响。线程的开销是很小的,但是不利于资源的管理和保护,进程则相反。
拓展 2.1、为什么程序计数器、虚拟机栈和本地方法区是私有的?
(1)程序计数器
程序计数器主要有两个作用:
1、字节码解释器通过改变程序计数器来依次读取指令,实现代码的流程控制。
2、在多线程的情况下,程序计数器用于记录当前线程的执行位置,以便于线程切换时能知道当前线程执行在什么位置。
所以程序计数器私有主要是为了线程切换后能恢复到正确的执行位置
。
(2)虚拟机栈
每个Java方法在执行的同时会产生一个栈帧,用于存储局部变量表、操作数栈、常量池引用等信息。从方法执行到结束的过程,就对应一个栈帧在Java
虚拟机栈中入栈和出栈的过程。
(3)本地方法区
和虚拟机栈所发挥的作用非常相似,区别是: 虚拟机栈为虚拟机执行 Java
方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot
虚拟机中和 Java 虚拟机栈合二为一。
为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法区得是线程私有的
。
拓展 2.2、简单了解堆和方法区
堆和方法区是所有线程共享的资源,其中堆是进程中最大的一块内存,堆中存储是所有新建的对象,方法区主要存放已被加载的类信息、常量、静态变量、即时编译后的代码数据等信息。
3、线程的生命周期和状态
Java线程在其生命周期中共有以下6中状态。
线程在其生命周期中不是固定于某一种状态,而是随着代码的执行在不同状态间切换。
操作系统隐藏 Java 虚拟机(JVM)中的 READY 和 RUNNING 状态,它只能看到 RUNNABLE 状态,所以 Java 系统一般将这两个状态统称为 RUNNABLE(运行中) 状态 。
线程创建之后处于NEW状态,直到调用start
方法开始运行,线程进入到READY(可运行)
状态,可运行线程获取到CPU
时间片之后进入到RUNNING(运行中)
状态。
拓展 3.1、为什么不直接调用RUN()方法,而要通过调用START()方法来执行RUN()方法
新建一个线程,线程位于新建状态,调用start()
方法后,启动
线程并进入准备就绪状态,当线程获取到CPU
时间段时,就会执行run()
方法中的逻辑,这是真正的多线程工作。但是直接执行run
方法,会把run
方法当作main
线程下的一个普通方法执行,不会在某个线程中启用它,这不是多线程工作。
4、线程的sleep方法和wait方法有什么异同点
(1)两者都可以暂停线程的执行。
(2)sleep方法没有释放锁,而wait方法释放了锁。
(3)wait方法用于线程间的交互/通信,sleep方法用于暂停线程。
(4)wait方法调用后,线程不会自动苏醒,需要别的线程调用同一个对象的的notify()
或者notifyAll()
方法。sleep方法执行完后,线程会自动苏醒。
wait(long timeout)
调用这个方法线程也会在指定时间自动苏醒。
下篇博文:Java高并发之多线程