进程和线程
进程
- 程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。在指令运行过程中需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的。
- 当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。
- 进程可以看做程序的一个实例。大部分程序可以同时运行多个实例(例如浏览器),有得只能启动一个实例进程(例如网易云音乐)。
线程
- 一个进程之内可以分为一到多个线程。
- 一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给CPU执行。
- Java中,线程作为最小的调度单位,进程作为资源最小的分配单位。
进程和线程对比
- 进程基本上是相互独立的,而线程存在于进程内,是进程的一个子集
- 进程拥有共享的资源,如内存空间等,供其内部线程共享
- 进程间通信较为复杂(同一台计算机进程通信称为IPC,不同计算机之间需要通过网络,遵守共同协议,如HTTP协议)
- 线程通信较为简单,同一进程内的线程共享内存,例如多线程访问共享资源
- 线程更轻量,线程上下文切换成本一般要比进程上下文切换成本低
并行和并发
并发
- 单核CPU,线程还是串行执行的。操作系统中有一个叫任务调度器的组件,将cpu时间片分给不同的线程使用,由于cpu在线程间的切换非常快,我们感觉是同时运行的。
- 微观串行,宏观并行
- 一般将线程轮流使用CPU的做法称为并发(concurrent)
并行
- 多核CPU下,每个核都可以调度运行线程,这时候线程可以是并行的
并发和并行比较
- 并发(concurrent)同一时间应对(dealing with)多件事情的能力
- 并行(parallel)同一时间动手做(doing)多件事情的能力
创建和运行线程
方法一:继承Thread类
@Slf4j(topic = "ants.extendThread")
public class ExtendThread extends Thread{
@Override
public void run() {
log.debug("创建线程一:继承Thread类,重写run方法");
}
public static void main(String[] args) {
ExtendThread extendThread = new ExtendThread();
extendThread.setName("t1");
extendThread.start();
}
}
方法二:实现Runnable接口
@Slf4j(topic = "ants.implRunnable")
public class ImplRunnable implements Runnable {
@Override
public void run() {
log.debug("实现Runnable接口,重写run(),创建线程");
}
public static void main(String[] args) {
Thread thread = new Thread(new ImplRunnable());
thread.setName("t1");
thread.start();
}
}
继承Thread类和实现Runnable接口创建线程比较
- 使用实现RUnnable接口的方式创建线程,分离了任务和线程之前的关系,代码更灵活
- 使用Runnable接口方式,更容易和线程池高级API结合
方法三:实现Callable接口
@Slf4j(topic = "ants.ImplCallable")
public class ImplCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
log.debug("run-----");
Thread.sleep(1000);
return 10;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> task = new FutureTask(new ImplCallable());
Thread t = new Thread(task);
t.start();
Integer o = task.get();
log.debug("result value:{}",o);
}
}
查看进程方法
windows
- tasklist:查看进程
- taskkill:杀死进程 taskkill /F /PID 进程号
Linux
- ps -ef|grep java
- top top -H -p 进程号 H:查看线程 -p:进程id 在top中查看进程id中所有线程信息
Java
- jps 插卡所有Java进程
- jstack pid 查看某个Java进程的所有线程状态
- jconsole 查看某个Java进程中线程的运行情况
线程运行原理
栈帧图解
栈帧图解.png
线程上下文切换
- 线程CPU时间片用完
- 垃圾回收
- 更高优先级线程执行
- 自己调用sleep、yield、synchronized等方法
上下文切换由程序计数器(Java方法)保存当前线程下一条执行的执行指令地址
上下文切换需要保存栈帧里面信息(局部变量表、返回地址、操作数栈等)
网友评论