线程

线程是比进程更轻量级的调度执行单位,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件I/O等),又可以独立调度。

实现线程的方式

内核线程
  1. 就是直接由操作系统内核支持的线程,由内核来完成线程切换,内核通过操纵调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。
  2. 程序一般不会直接使用内核线程,而是使用内核线程的一种高级接口——轻量级进程。
  3. 轻量级进程局限性:基于内核线程实现的,创建、析构及同步操作,都需要进行系统调度;每个轻量级进程都需要一个内核线程的支持,要消耗一定的内核资源(如内核线程的栈空间)。



java 的内核空间和用户空间 java用户线程和内核线程_java是内核线程还是用户线程

内核线程



用户线程
  1. 完全建立在用户空间的线程库上,用户线程的建立、同步、销毁和调度完全在用户态中完成。
  2. 用户线程的优势:不需要系统内核支援
  3. 用户线程的劣势:因为没有系统内核的支援,所有线程操作都需要由用户程序自己处理。



java 的内核空间和用户空间 java用户线程和内核线程_用户级别线程的切换切换到内核线程_02

用户线程



混合线程
  1. 内核线程与用户线程一起使用。既存在用户线程,也存在轻量级进程。
  2. 用户线程完全建立在用户空间中,用户线程的创建、切换、析构等操作消耗的资源少,并可以支持大规模的用户线程并发。
  3. 轻量级进程则作为用户线程与核心线程之间的桥梁,可以提供线程调度及处理器映射,并用户线程的系统调用通过轻量级进程完成,降低了整个进度被阻塞的风险。



java 的内核空间和用户空间 java用户线程和内核线程_用户级别线程的切换切换到内核线程_03

混合线程



Java线程调度

  1. 协同式:线程的执行时间由线程本身控制,线程把自己的工作执行完了之后,要主动通知系统切换到另外一个线程上去。
  2. 协同式多线程的最大好处是实现简单,而且由于线程要把自己的事情干完后才会线程切换,切换操作对线程自己是可知的,不会出现线程同步的问题。
  3. 协同式线程的坏处,线程执行时间不可控制,如果一个线程的代码编写有问题,一直不通知系统进行线程切换,那么程序会一直阻塞。
  4. 抢占式:每个线程将由系统来分配执行时间,线程的切换不由线程本身来决定。例如Thread::yield()方法可以主动让执行时间是系统可控的。不会有一个线程导致整个进行甚至系统阻塞。

线程状态

  1. 新建(New):创建后尚未启动的线程
  2. 运行(Runnable):包括操作系统线程状态中的Running和Ready,也就是处于此状态的线程有可能正在执行,也有可能正在等待着操作系统为它分配执行时间。
  3. 无限期等待(Waiting):不会被分配处理器执行时间,它们要等待被其他线程显式唤醒。
  1. 没有设置Timeout参数的Object::wait()方法
  2. 没有设置Timeout参数的Thread::join()方法
  3. LockSupport::park()方法
  1. 限期等待(Timed Waiting):不会被分配处理器执行时间,不过无须等待被其他线程显式唤醒,在一定时间之后他们会由系统自动唤醒。
  1. Thread::sleep()方法
  2. 设置了Timeout参数的Object::wait()方法
  3. 设置了Timeout参数的Thread::join()方法
  4. LockSupport::parkNanos()方法
  5. LockSupport::parkUntil()方法
  1. 阻塞(Blocked):线程被阻塞了,"阻塞状态"与"等待状态"的区别是"阻塞状态"在等待着获取到一个排它锁,这个事件将在另外一个下次呢很那个放弃这个锁的时候发生;而"等待状态"则是在等待一段时间,或者唤醒动作的发生。
  2. 结束(Terminated):已终止线程的线程状态,线程已经结束执行。



java 的内核空间和用户空间 java用户线程和内核线程_java 的内核空间和用户空间_04

线程状态转换图