什么是多线程的上下文切换?
上下文切换是指 CPU 从一个线程转到另外一个线程时,需要保存当前线程的上下文状态,恢复另一个线程的上下文状态,以便于下一次恢复执行该线程时能够正确的运行。
在多线编程中,上下文切换是一种常见的操作,上下文切换通常是指在一个 CPU 上,由于多个线程共享 CPU 时间片,当一个线程的时间片用完后,需要切换到另一个线程运行。此时需要保存当前线程的状态信息,包括程序计数器、寄存器、栈指针等,以便下次继续执行该线程时能够恢复到正确的执行状态。同时,需要将切换到的线程的状态信息恢复,以便于该线程能够正确运行。
在多线程中,上下文切换的开销比直接用单线程大,因为在多线程中,需要保存和恢复更多的上下文信息。过多的上下文切换会降低系统的运行效率,因此需要尽可能减少上下文切换的次数。
什么是线程安全?
线程安全是指某个函数在并发环境中被调用时,能够正确处理多个线程间的共享变量,使程序功能正确完成。
什么是并发,什么是并行?
并发(Concurrent),指的是多个任务在一段时间内重叠执行,但并不一定同时进行。它强调任务的交错执行和资源共享。
并行(Parallelism),指的是多个任务在同一时刻真正同时执行。它强调计算资源的利用和计算能力的提升。
线程的几种状态
- 初始(NEW):新创建了一个线程对象,但还没有调用 start() 方法。
- 运行(RUNNABLE):Java 线程中将就绪(READY)和运行中(RUNNING)两种状态笼统的称为“运行”。
就绪(READY):线程对象创建后,其他线程调用了该对象的 start() 方法。该状态的线程位于可运行线程池中,等待被线程调度选中并分配 CPU 使用权。
运行中(RUNNING):就绪(READY) 的线程获得了 CPU 的时间片,开始执行程序代码。 - 阻塞(BLOCKED):表示线程阻塞于锁。
- 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
- 超时等待(TIMED_WAITING):该状态不同于 WAITING ,它可以在指定的时间后自行返回。
- 终止(TERMINATED):表示该线程已经执行完毕。
WAITING 和 TIMED_WAITING 的区别
在 Java 中调用 wait() 方法时,线程会进入到 WAITING 状态,线程执行 sleep() 方法时,线程会进入 TIMED_WAITING 状态。
sleep() 方法可以在任何地方使用,而 wait() 方法只能在同步方法或同步块中使用。
处于 WAITING 和 TIMED_WAITING 的线程,都是会让出 CPU 的,但是它们在对象的锁释放上并不一样,如果加了锁,sleep() 方法不会释放对象上的锁,而 wait() 方法是会释放锁的。
创建线程的几种方式
在 Java 中共有 4 种方式创建线程:
- 继承 Thread 类创建线程
- 实现 Runnable 接口创建线程
- 通过 Callable 和 Future Task 创建线程
- 通过 线程池 创建线程
其实本质上一共就两种,一个是继承 Thread 类,一个是实现 Runnable 接口,至于其他的也是基于这两个方式实现的。
Runnable 和 Callable 的区别
实现 Runnable 的时候,需要实现 run() 方法,实现 Callable 接口的话,需要实现 call() 方法。
Runnable 的 run() 方法无返回值,Callable 的 call() 方法有返回值,类型为 Object。