业务场景:小明去理发店理发。
小明去理发店理发,完成理发需要吹,剪,洗、理的过程。由这个场景我们引用进程和线程这两个
概念。
一.进程
1.什么是进程
进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的独立单位。进程是可与其他程序并发执行的程序,在一个数据集合上的运行过程。它是系统进行资源分配和调度的一个独立单位。
大家打开windows的任务管理器就可以看到,系统运行的进程。
2.进程的几个概念
2.1 结构性
为了控制和管理进程,系统为每个进程设立一个**进程控制块\- PCB。
每个进程拥有一个控制块(PCB),这是进程存在的依据,用于描述和记录进程的动态变化过程,并使之能正确运行。
2.2 动态性
进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的,进程在其生命周期内,在三种基本状态(产生、执行、消亡)之间转换。
进程是程序在处理机上的一次动态执行过程。它因创建而产生,由调度而执行,因得不到资源而暂停执行,最后因撤销而消亡。
2.3 异步性
由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。
系统中的各进程以独立的、不可预知的速度向前推进。
2.4 并发性
任何进程都可以同其他进程一起向前推进。
多个进程实体可以同时存在于内存中,在一段时间内都得到运行,它们在执行时间上是重叠的。
2.5 独立性
进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
进程是能独立运行的基本单位,也是系统进行资源分配和调度的独立单位。
二.线程
我们把理发这个进程分解为几个子任务(线程)如下:
1.线程的定义
1.1 线程是程序执行的**最小单位\,而进程是操作系统分配资源的最小单位;
1.2 一个进程由一个或多个线程组成,线程是一个进程中代码的**不同执行路线\;
1.3 进程之间相互独立,但同一进程下的**各个线程之间共享程序的内存空间(包括代码段,数据 集,堆等)及一些进程级的资源(如打开文件和信号等),某进程内的线程在其他进程不可见;
1.4 调度和切换:线程上下文切换比进程**上下文切换要快得多\;
2.线程和进程的区别
3.线程的切换方式
三.线程的生命周期
1.线程创建
1.1 继承Thread类
public class ThreadDemo extends Thread{
public ThreadDemo(String name){
setName(name);
}
public void run(){
for (int i = 1;i <= 100;i++){
System.out.println(getName() + ":" + i);
if (i==5) throw new RuntimeException("死亡");
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new ThreadDemo("A");
Thread t2 = new ThreadDemo("B");
t2.start();//ready
t1.start();//ready
// Thread.sleep(100);
// System.out.println("main");
}
}
1.2 实现Runnable接口
/**
* 实现Runnable接口
*/
public class ThreadDemo02 implements Runnable{
private String name;
public ThreadDemo02(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 0;i < 10;i++){
System.out.println(this.name + "---" + i);
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new ThreadDemo02("A"));
Thread t2 = new Thread(new ThreadDemo02("B"));
t2.start();
t1.start();
}
}
1.3 实现Callable接口
public class ThreadDemo01 implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 1; i < 1000; i++) {
sum += i;
}
return sum;
}
public static void main(String[] args) throws Exception {
FutureTask<Integer> ft =
new FutureTask<Integer>(new ThreadDemo01());
ft.run();
System.*out\*.println("s:" + ft.get());
}
}
2.线程就绪
Thread t = new Thread( );
t.start( ); //启动线程(线程就绪)
3.线程运行
一旦CPU分配了运行时间,就调用线程的run( )方法。
4.线程阻塞
线程阻塞可以分为以下几种类型:
1.等待阻塞:线程调用wait()方法,进入等待状态,等待其他线程的通知或者中断。
2.同步阻塞:线程在获取对象锁时,如果该锁被其他线程占用,则进入同步阻塞状态。
3.睡眠阻塞:线程调用sleep()方法,进入睡眠状态,等待一定时间后自动唤醒。
4.IO阻塞:线程在执行IO操作时,如果IO操作没有完成,则进入IO阻塞状态。
5.其他阻塞:线程调用join()方法等待其他线程执行完毕,或者调用yield()方法主动让出CPU资源。
5.线程死亡
线程死亡是线程生命周期的一个重要阶段。线程在完成其任务后自动进入死亡状态。当一个线程完成其执行,或因未捕获的异常而退出时,该线程将进入死亡状态,此时线程的所有资源将被释放。
线程死亡的条件:
1.正常结束:线程执行完run()方法。
2.异常结束:在线程执行过程中出现未处理的异常。
3.被强制终止:其他线程调用stop()等方法。
四.守护线程与用户线程
1.用户线程User Thread(创建的线程)
不需要内核支持而在用户程序中实现的线程
用户线程指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。
2.守护线程Daemon Thread(守护最后一个用户线程才结束)
守护线程是指在程序运行的时候在后台提供一种通用服务的线程,比如垃圾回收线程就是一个很称职的守护者,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 守护线程
*/
public class ShouHuDemo {
public static void main(String[] args) throws Exception{
Thread t1 = new Thread(() -> {
while (true){
try {
Date now = new Date();
long s1 = now.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd hh:mm:ss");
Date parse = sdf.parse("24-09-15 17:15:00");
System.out.println(sdf.format(now));
long s2 = parse.getTime();
System.out.println("s1:" + s1 + "s2:" + s2);
if (s1 == s2){
System.out.println("到点了!!!");
}
Thread.sleep(1000);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0;i < 100;i++){
try {
System.out.println("o" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t1.setDaemon(true);
t1.start();
t2.start();
}
}