线程

进程与线程

进程是所有线程的集合,每一个线程是进程中的一条执行路径

线程API之间的关系

202022320208

线程分类

HotSpot的每一个Java线程都是直接映射到一个操作系统原生线程来实现的

创建线程

继承Thread类

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

多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈

批注 2019-08-02 115159

Thread类

InterruptedException

调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞(sleep)、限期等待或者无限期等待(wait)状态,那么就会抛出 InterruptedException,从而提前结束该线程

interrupted()

在自定义线程执行任务使,可以使用这个方法作为一个flag,作为是否继续运行的依据

while(interrupted()){
    // do
}
// end

实现Runnable接口

实现Runnable接口比继承Thread类所具有的优势:

Thread相关源码

初始化

private Thread(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();
        if (g == null) {
           
            if (security != null) {
                g = security.getThreadGroup();
            }

            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        g.checkAccess();
        // 权限检查
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(
                        SecurityConstants.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)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        // 设置线程栈大小
        this.stackSize = stackSize;

        /* Set thread ID */
        this.tid = nextThreadID();
    }

启动

public synchronized void start() {
    // 线程并非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) {
            /* do nothing. If start0 threw a Throwable then
              it will be passed up the call stack */
        }
    }
}

join

join 的意思就是当前线程(currentThread)等待另一个线程(调用join的那个线程)执行完成之后,才能继续操作

public final synchronized void join(final long millis)
throws InterruptedException {
    if (millis > 0) {
        // 判断自身是否已执行完毕,
        if (isAlive()) {
            // 如果还未完毕等待一定的时间
            final long startTime = System.nanoTime();
            long delay = millis;
            do {
                wait(delay);
            } while (isAlive() && (delay = millis -
                    TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)) > 0);
        }
    // 无限等待
    } else if (millis == 0) {
        // 原理就是自旋判断自身是否已经执行完毕
        while (isAlive()) {
            // 如果还未执行完毕,则进入wait
            wait(0);
        }
    } else {
        throw new IllegalArgumentException("timeout value is negative");
    }
}

线程调度

可以通过Thread实例setPriority来调整优先级,不过此举总体而言不是一个稳定的调节手段

线程状态

stateDiagram-v2
    direction LR
    state RUNNABLE {
        READY --> RUNNING: 线程被调度器选中
        RUNNING --> READY: 线程被挂起/yield
    }
    NEW --> RUNNABLE: start()
    RUNNABLE --> TERMINATERD: 运行结束或异常退出
    RUNNABLE --> WAITING: Object.wait()/Thread,join()/LockSupport.park()
    WAITING --> RUNNABLE: Object.notify()/Object.notifyAll()/LockSupport.unpark()
    RUNNABLE --> BLOCKED: 阻塞IO/synchorized
    BLOCKED --> RUNNABLE: 获得锁
    RUNNABLE --> TIME_WAITING: Thread.sleep()/Object.wait()/LockSupport.parkUntil()
    TIME_WAITING --> RUNNABLE: 超时/Object.notify()/Object.notifyAll()
线程状态 导致状态发生条件
NEW(新建) 线程刚被创建,但是并未启动。还没调用start方法。
Runnable(可运行) 线程可以在java虚拟机中运行的状态,可能正在运行自己代码,也可能没有,这取决于操 作系统处理器。
Blocked(锁阻塞) 当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状 态;当该线程持有锁时,该线程将变成Runnable状态。
Waiting(无限等待) 一个线程在等待另一个线程执行一个(唤醒)动作时,该线程进入Waiting状态。进入这个 状态后是不能自动唤醒的,必须等待另一个线程调用notify或者notifyAll方法才能够唤醒。
Timed Waiting(计时等待) 同waiting状态,有几个方法有超时参数,调用他们将进入Timed Waiting状态。这一状态 将一直保持到超时期满或者接收到唤醒通知。带有超时参数的常用方法有Thread.sleep 、 Object.wait。
Teminated(被终止) 因为run方法正常退出而死亡,或者因为没有捕获的异常终止了run方法而死亡。