zl程序教程

您现在的位置是:首页 >  Java

当前栏目

并发编程(一)-Thread 源码分析

2023-04-18 16:51:27 时间

一、什么是线程


线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。

二、线程创建方式


2.1 继承Thread

public class MyThread extends Thread{
   @Override
   public void run(){
       
  }
}

2.2 实现Runnable接口

public class MyThread implements Runnable(){
   @Override
   public void run(){
       
  }
}

2.3 实现Callable接口

public class MyThread implements Callable<Integer> {

  @Override
  public Integer call() throws Exception {
      return 0;
  }
}

从Diagrams 图中就可得知,不管是extends Thread 还是 implements Callable接口,底层归根到底还是,实现了Runnable接口。

三、源码分析


3.1 线程中属性含义


// 线程名称
private volatile String name;
// 线程优先级
private int            priority;
// 内置的Thread类
private Thread         threadQ;
// JVM中的java thread 指针
private long           eetop;

// 是否是单步执行此线程
private boolean     single_step;

// 是否是守护线程
private boolean     daemon = false;

// jvm 状态
private boolean     stillborn = false;

// 构造函数中会传入的线程对象
private Runnable target;

// 线程组
private ThreadGroup group;

// 类加载器
private ClassLoader contextClassLoader;

// 继承的访问下文
private AccessControlContext inheritedAccessControlContext;

// 静态变量,使用内部静态类的单例模式,全局存在,用来生成线程名
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
   return threadInitNumber++;
}

// ThreadLocal 能为线程设置线程私有变量,设置线程上下文
ThreadLocal.ThreadLocalMap threadLocals = null;

// inheritableThreadLocals 解决子线程能够获取父线程变量
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

// 给线程分配的栈大小,线程默认栈大小为0
private long stackSize;

// 本地线程终止之后的专用状态
private long nativeParkEventPointer;

// 线程id
private long tid;

// 用于生成线程id,新创建线程后自增
private static long threadSeqNumber;

// 线程状态,初始线程状态:0
private volatile int threadStatus = 0;

// 生成线程id方法
private static synchronized long nextThreadID() {
   return ++threadSeqNumber;
}

// LockSupport 中断
volatile Object parkBlocker;

// interrupt 相关
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
void blockedOn(Interruptible b) {
   synchronized (blockerLock) {
       blocker = b;
  }
}

// 线程最低优先级
public final static int MIN_PRIORITY = 1;

// 线程默认优先级
public final static int NORM_PRIORITY = 5;

// 线程最高优先级
public final static int MAX_PRIORITY = 10;

3.2 线程状态

public enum State {
  // 新建状态:Thread t = new Thread();
  NEW,

  // 运行,调用了t.start(),此时就绪(等待CPU进行调度)和运行都属于运行状态。
  RUNNABLE,

  // 阻塞,因为争用 synchronized 的 monitor 对象而发生阻塞的线程处于 blocked 状态。
  BLOCKED,

  // 等待,需要其他的线程进行唤醒。一般是调用Object.wait,Thread.join,LockSupport.park
  WAITING。可以调用Object.notify,Object.notifyAll,LockSupport.unpark进行唤醒

  // 超时等待,可以在指定时间内自动唤醒。调用Thread.sleep(long),Object.wait(long),Thread.join(long),
  // LockSupport.parkNanos(long),LockSupport.parkUntil(long)等进入TIMED_WAITING状态。
  // 唤醒方式:时间到了,Object.notify,Object.notifyAll,LockSupport.unpark等方法
  TIMED_WAITING,

  // 终止线程的线程状态。线程已完成执行。
  TERMINATED;
}

3.3构造方法

3.3.1 jdk1.8中Thread

3.4 init方法


private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc,
                  boolean inheritThreadLocals) {
    // 线程名称校验
    if (name == null) {
        throw new NullPointerException("name cannot be null");
    }

    this.name = name;
  // 父线程
    Thread parent = currentThread();
    // 获取安全管理器
    SecurityManager security = System.getSecurityManager();
    // 线程组为null
    if (g == null) {
        // 安全管理器不为null,从安全管理器中获取线程组
        if (security != null) {
            g = security.getThreadGroup();
        }
        // 线程组为null,则从父线程中获取线程组
        if (g == null) {
            g = parent.getThreadGroup();
        }
    }
  // 检查当前线程拥有线程组权限
    g.checkAccess();

    if (security != null) {
        if (isCCLOverridden(getClass())) {
            security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
        }
    }
  // 添加未启动线程数
    g.addUnstarted();
  
    this.group = g;
    // 设置守护线程标识
    this.daemon = parent.isDaemon();
    // 获取线程优先级
    this.priority = parent.getPriority();
    // 设置类加载器
    if (security == null || isCCLOverridden(parent.getClass()))
        this.contextClassLoader = parent.getContextClassLoader();
    else
        this.contextClassLoader = parent.contextClassLoader;   
    this.inheritedAccessControlContext =
            acc != null ? acc : AccessController.getContext();
    this.target = target;
    // 设置线程优先级
    setPriority(priority);
    if (inheritThreadLocals && parent.inheritableThreadLocals != null)
        // 子线程集成父线程的ThreadLocal
        this.inheritableThreadLocals =
            ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    // 设置线程栈大小
    this.stackSize = stackSize;
    // 设置线程id
    tid = nextThreadID();
}

3.5 start方法

public synchronized void start() {
   // 检查线程状态是否是初始化状态( 0 == NEW)
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
  // 线程组中添加该线程
    group.add(this);
    boolean started = false;
    try {
        // 调用native方法
        start0();
        // 成功启动标识
        started = true;
    } finally {
        try {
            // 没有启动成功
            if (!started) {
                // 从线程组中移除启动失败的线程
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}

private native void start0()

3.6 run方法


public void run() {
    if (target != null) {
        // 调用构造函数Runnable的run方法
        target.run();
    }
}

3.7 interrupt方法

interrupt并不是强制中断停止线程,仅仅更改线程状态。被设置中断标志的线程将继续正常运行,不受影响。


public void interrupt() {
    if (this != Thread.currentThread())
        checkAccess();

    synchronized (blockerLock) {
        Interruptible b = blocker;
        if (b != null) {
            // 设置中断状态
            interrupt0();         
            // 调用阻断程序中的中断方法
            b.interrupt(this);
            return;
        }
    }
    interrupt0();
}

3.8 enumerate方法

// 将当前线程组及其子线程组的线程复制到指定数组中
public static int enumerate(Thread tarray[]) {
    return currentThread().getThreadGroup().enumerate(tarray);
}

3.9 join(long millis)方法


public final synchronized void join(long millis)throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;
  // 等待毫秒数为负数,则抛出异常  
    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }
  // 等待毫秒数等于0,会一直等待,直到线程死亡,原理就是自旋等待
    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    } else {
      // 等待毫秒数大于0,超出等待时间,则退出。超时自旋等待
        while (isAlive()) {
            long delay = millis - now;
            // 如果等待时间小于等于0,退出等待
            if (delay <= 0) {
                break;
            }
            // 调用wait方法进行线程等待
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

3.10 sleep(long millis, int nanos)方法

线程休眠,线程休眠会将线程的cpu释放,但是线程占有的锁不会释放,当前线程进入Timed_waiting。

public static void sleep(long millis, int nanos)throws InterruptedException {
    // 睡眠毫秒实际小于0,抛出异常
    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }
  // 睡眠纳秒时间 0~999999,
    if (nanos < 0 || nanos > 999999) {
        throw new IllegalArgumentException(
                            "nanosecond timeout value out of range");
    }
  // 1毫秒 = 1000000纳秒,纳秒数据超过一般0.5毫秒数据,就当做1毫秒,或者毫秒是0 而毫秒非零,也加1
    if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
        millis++;
    }
  // 调用native方法,线程休眠
    sleep(millis);
}

3.11 yield方法

yield是 Thread 类中的native方法,作用:让出当前线程CPU的时间片,使当前线程从执行状态变为就绪状态,cpu将会从就绪队列中重新选择一个线程,也就是说,当前线程还是有可能会被再次选择的。