基本概念: 程序、进程、线程
程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
进程(process)是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。——生命周期
如:运行中的QQ,运行中的MP3播放器
程序是静态的,进程是动态的
进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。
若一个进程同一时间 并行 执行多个线程,就是支持多线程的(并行强调同一个时间点)
线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开 销小
一个进程中的多个线程共享相同的内存单元/内存地址空间--->它们从同一堆中分配对象,可以 访问相同的变量和对象。这就使得线程间通信更简便、高效。
但多个线程操作共享的系统资源可能就会带来安全的隐患。
比如说java程序,一方面我需要起一个main方法对应的主线程去拷我们的程序,同时还有自动的垃圾回收,你不能等我的main方法执行完再回收,否则有可能过程中垃圾太多导致溢出。所以我们的main方法执行时后台最好再跟进一个垃圾回收的线程,这时一边执行,一边回收.
线程的创建和使用(重点)(这里先介绍两种)
JDK1.5前:
1. 如果自己手动调用run()方法,那么就只是普通方法,没有启动多线程模式。
2. run()方法由JVM调用,什么时候调用,执行的过程控制都由操作系统的CPU 调度决定。
3. 想要启动多线程,必须调用start方法。
4. 一个线程对象只能调用一次start()方法启动,如果重复调用了,则将抛出以上的异常“IllegalThreadStateException”。
线程的调度
Java中用到的线程调度算法是什么?
有两种调度模型:分时调度模型和抢占式调度模型。
分时调度模型是指所有的线程轮流获得CPU的使用权,并且平均分配每个线程占用的CPU的时间片。
而Java虚拟机采用的是抢占式调度模型,是指优先让运行池中优先级高的线程占用CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用该CPU。处于运行状态的线程会一直运行,直到它不得不放弃CPU。
线程的生命周期
其实阻塞状态的情况有三种:
1.等待阻塞:运行状态中的线程执行 wait()方法,JVM会把该线程放入到等待队列(waitting queue)中,使本线程进入到等待阻塞的状态;
,2.同步阻塞:线程在获取synchronized同步锁失败(因为锁会被其他线程所占用)后,则JVM会把该线程放入到放入到锁池(lock pool)中,线程会进入同步阻塞状态;
3.其他阻塞:通过调用线程的sleep()、join()、发出了I/O请求时,线程会进入阻塞状态。当sleep()状态超时,join()等待线程终止或超时、I/O处理完毕时,线程重新转入就绪状态。
线程的同步
例子:模拟火车站售票程序,开启三个窗口售票。(面试时可以用这个例子引出来,或者是存取钱的例子)
实现一个由A、B、C三个窗口同时销售100张票的系统,要求打印出每个窗口打印的售票情况,并且每个窗口不得连续售票
其实造成死锁有四个条件:
1.互斥条件
2.请求与保持条件
3.不剥夺条件
4.循环等待条件
线程的通信
/**
* @author xiaocui
* @date 2022年08月03日 10:50
*/
public class CommunicationThread implements Runnable {
int i = 1;
@Override
public void run() {
while (true) {
synchronized (this) {
notify();
if (i <= 100) {
System.out.println(Thread.currentThread().getName() + ":" + i++);
} else
break;
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
JDK5.0新增线程创建方式
什么是Callable和Future?
1.把Callable与Runnable的区别说一下,体现Callable的功能强大;
2.Callable与Future的关系:Callable被线程执行之后,可以返回值,这个返回值被Future拿到,也就是说,Future可以拿到 异步执行任务 的返回值。
3.Future接口表示异步任务,是一个可能还没完成的异步任务的结构。所以Callable用于产生结构,Future用于获取结果。