一文搞懂线程和进程
前置知识
区分线程和进程
什么是进程?
是操作系统进行资源分配和调度的基本单位。
什么是进程状态?
一个进程的生命周期可以划分为一组状态,进程状态标志了进程处于生命周期的哪个阶段。它反应了程序的执行过程。
下图黄色文字代表操作系统中进程状态,即
活的进程(抛开线程的出生和死亡)至少有3种状态:
- 就绪态:具备了运行条件,等待CPU分配处理资源
- 运行态:CPU正在执行
- 等待态:又叫阻塞态,指进程正在等待某件事情的完成,不能够运行。
另外两种状态:
- 新建态:对应进程刚刚被创建的状态。创建进程有两个步骤:第一步:为新进程创建进程管理块;第二步:让该进程进入就绪态。
- 终止态:不再执行的进程,但是依然保留在操作系统中等待着善后。一旦其他进程完成了对终止态的进程的信息的抽取之后,操作系统将删除该进程。
可能存在的状态转换:
- null----->新建态:执行程序,创建一个子进程。
- 新建态----->就绪态:在当前系统性能和内存容量允许的情况下,操作系统完成了进程创建的必要操作。
- 终止态----->null:完成善后操作,释放内存。
- 运行态---->终止态:进程到打程序节点,寿终正寝。或者出现了无法克服的错误,或者被操作系统所终结(强制关机),或者被父进程所终结。
- 就绪态—>终止态:父进程终结子进程
- 等待态—>终止态:父进程终结子进程
进程可能的状态转换有哪些?
- 就绪态----->运行态:CPU空闲时,从就绪状态的进程中选一个来执行。这里相当于是在等CPU来执行我这个进程。
- 运行态----->就绪态:CPU分给每个进程的时间片是有限的,该进程的运行时间一用完,CPU就跑去执行其他进程去了。或者在执行过程中,碰到了一个拥有更高优先权的进程,也会让CPU放弃当前执行的线程,转而去执行优先级更高的进程。此时,则当前进程从运行态转换成了就绪态。
- 运行态---->等待态:正在执行的进程发生了某个等待事件而无法执行,比如:发生了I/O请求(等待外设传输)
CPU的时间很宝贵,不会一直在这里等你。
- 等待态----->就绪态:进程所等待的事件已经结束,这时进程进入到就绪队列中。
状态转化图(三态模型)
2种不可能存在的转换
- 等待态----> 运行态:这之间隔了一个就绪态。CPU只会从就绪状态的队列中选择进程来执行。
- 就绪态----> 等待态:这之间隔了运行态,进程没有执行,不可能会到等待态。
黑色文字代表线程状态,即
- 新建,new
- 可运行,runnable
- 计时等待
- 无限等待
- 锁阻塞
- 终止,terminated
什么是线程?
是进程内部的一个独立的执行单元。一个进程可以并发的运行多个线程。可以将进程看做是一个单CPU操作系统,而线程就是这个系统中运行的多个任务。
注意事项
亮点
- JVM采用的是抢占式调度,有点类似于非公平锁的机制。这造成了线程分配的随机性。
- JVM负责线程的调度
线程有哪几种状态?
- NEW,刚刚创建,尚未启动
- RUNNABLE,可运行
- BLOCKED,锁被其他线程占有。
- WAITING,无限期等待另一个线程执行结束,等着别人叫醒它。(notify)
- TIMED_WAITING,计时等待。
- TERMINATED,已经退出的线程
线程之间的转换是怎样的?
创建线程的几种方式
方式一:继承thread类
第一步:自定义一个线程类,重写run方法
package cn.lizemin.demo.thread;
/**
* @author: lizemin
* @version: 1.0
*/
public class MyThread extends Thread{
public MyThread(String name){
super(name);
}
@Override
public void run() {
for (int i = 0; i < 20; i++) {
//打印当前线程的名字
System.out.println(getName()+" "+i);
}
}
}
第二步:启动多线程,ThreadDemo
package cn.lizemin.demo.thread;
/**
* @author: lizemin
* @version: 1.0
* 使用方法一:
* 1.自定义一个类继承thread类
* 2.run方法中放新的线程要执行的代码
*/
public class ThreadDemo{
//这是一个main方法,是程序的入口
public static void main(String[] args) {
System.out.println("main线程已开启");
//创建线程对象
MyThread myThread = new MyThread("小强");
//开启新的线程
myThread.start();
for (int i = 0; i < 20; i++) {
System.out.println("旺财:"+i);
}
}
}
第三步:执行代码
可以看到两个线程交替执行,旺财和小强交替出现。
方式二:定义自定义类实现runnable接口
1.自定义实现runnable接口,MyRunnable,并实现run方法。
package cn.lizemin.demo.thread;
/**
* @author: lizemin
* @version: 1.0
*/
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
//打印当前线程的名字
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
2.创建自定义类对象,在创建thread对象时,将其作为thread对象的参数传递。
package cn.lizemin.demo.thread;
/**
* @author: lizemin
* @version: 1.0
* 2.run方法中放新的线程要执行的代码
*/
public class ThreadDemo{
//这是一个main方法,是程序的入口
public static void main(String[] args) {
System.out.println("main线程已开启");
MyRunnable myRunnable = new MyRunnable();
//创建线程对象
Thread thread = new Thread(myRunnable,"小强");
Thread thread2 = new Thread(myRunnable,"旺财");
//开启线程
thread.start();
thread2.start();
}
}
查看线程的状态
package cn.lizemin.demo.thread;
/**
* @author: lizemin
* @version: 1.0
* 使用方法一:
* 1.自定义一个类继承thread类
* 2.run方法中放新的线程要执行的代码
*/
public class ThreadDemo{
//这是一个main方法,是程序的入口
public static void main(String[] args) throws InterruptedException {
System.out.println("main线程已开启");
MyRunnable myRunnable = new MyRunnable();
//创建线程对象
Thread thread = new Thread(myRunnable,"小强");
Thread thread2 = new Thread(myRunnable,"旺财");
//创建线程对象后,查看线程状态:new
System.out.println("thread当前的线程状态为:"+thread2.getState());
//开启线程
thread.start();
thread2.start();
//开启线程后,查看线程状态:runnable
System.out.println("thread当前的线程状态为:"+thread2.getState());
Thread.sleep(500);
//线程沉睡后,查看线程状态:TERMINATED
System.out.println("thread当前的线程状态为:"+thread2.getState());
}
}
流程图
当线程结束后,会进入到终止状态