Java-第十六部分-JUC-线程

174 阅读3分钟

JUC全文

用户态和内核态

  • 用户态,用户的应用程序
  • 内核态,调用内核的系统调用

系统调用,操作系统最小的功能单位 image.png

  • shell,特殊的应用程序,下通系统调用,上通用户应用,来连接各个小功能的程度,通过shell脚本,可以调用系统调用
  • 当用户应用,涉及到需要调用系统调用的时候,就会切换为内核态,消耗内核资源

线程的实现

内核线程

  • Kernel-Level Thread,KLT
  • 由内核完成线程切换,内核通过调度器对线程进行调度,并将线程任务映射到各个处理器上
  • 程序通过使用轻量级进程,Light Weight Process,LWP(实际意义上的线程),来调用内核线程
  • 优点,每个LWP都是独立的调度单元,一个LWP被阻塞,并不会影响其他LWP
  • 缺点,基于KLT,耗费资源,线程的创建和同步都需要系统调用,进行频繁的用户态/内核态切换

用户线程

  • User Thread,UT
  • 广义,非内核线程,包括LWP(需要调用内核线程来完成)
  • 狭义,建立在用户控件的线程库上,内核不能感知这些线程的实现,只有当前用户进程能够管理这些用户线程
  • 优点,用户线程的创建、同步、销毁和调度完全在用户态,不需要内核
  • 缺点,需要用户控制实际的线程调度,如何发挥多处理器系统的特点,将多线程映射到其他处理器

线程的转换

  • 线程状态
public enum State {
    //新建
    NEW,
    //准备就绪
    RUNNABLE,
    //阻塞
    BLOCKED,
    //不见不散,
    WAITING,
    //过时不候
    TIMED_WAITING,
    //终结
    TERMINATED;
}

New

  • 新建状态,但还不是一个真正的线程
Thread thread = new Thread();

Runnable

  • 开始真正创建一个线程,开始运行,并加入到线程组
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread());
    }
});
thread.start();

image.png

  • 真正调用内核方法start0,真正创建一个线程pthread_create,与内核线程进行对应
private native void start0();
  • 可以细分为Ready/Running

区别为,是否等待到了资源并开始运行

Terminated

  • 一个线程执行完毕
  • 调用thread.stop();,此方法已被抛弃
  • 线程状态不可逆,无法再复活

wait方法

  • 锁对象来调用
  • 线程状态为WAITING
this.wait(); 
  • 线程状态为TIMED_WAITING
this.wait(1000);
Thread.sleep(1000)

底层实现

  • 如果锁对象为偏向锁,那么必须膨胀成重量级锁,才能进行wait,因为要调用锁对象中的monitorwait方法
  • 将当前线程封装成ObjectWaiter对象,加入锁对象的monitor中的waitSet队列末尾
  • 释放锁对象,通过底层的park方法挂起
  • wait方法实际上是一个循环,当时间到了/中断/notify会进行唤醒

notify

  • 唤醒线程重新争抢锁,从哪里wait,就从哪里被notify
  • 实际上,notify只是将线程从waitSet队列队首取出,放入cxq/EntryList中,直到锁对象exit,根据唤醒策略进行获得锁
  1. 放入EntryList队首
  2. 放入EntryList队尾
  3. EntryList为空,直接放到EntryList,放入cxq队首
  4. 放入cxq队尾
  • notifyAll实际上是遍历waitSet唤醒所有线程

Blocked

  • 针对synchronized当线程在等待锁的释放时候,会进入阻塞的状态

小结

  • Blocked线程一定在EntryList/cxq队列中
  • Waiting/Timed_waiting线程,有可能是执行了park和sleep,不一定在waitSet中,只有执行了wait,才会被加入waitSet

与进程的区别

  • 最小单位
  1. 进程是资源分配的最小单位
  2. 线程是CPU调度的最小单位
  • 内存
  1. 进程有自己独立的内存空间
  2. 线程共享内存,JVM中在堆空间有私有的TLAB
  • 一个程序至少有一个进程,一个进程至少有一个线程
  • 一个线程可以创建和撤销另一个线程,同一个进程中的多个线程可以并发执行