Java多线程之Thread源码分析

一:Thread是什么

线程Thread是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。 Java程序运行时,会启动一个JVM进程,JVM寻找到程序的入口main(),会创建一个主线程运行。一个java程序至少有一个进程,一个进程至少有一个线程。

二:线程的创建与使用

  1. 继承Thread,重写run方法
    class MyThread extends Thread {
        @Override
        public void run() {
            // do something
            super.run();
        }
    }
    
    MyThread myThread = new MyThread();
    myThread.start();
复制代码
  1. 实现Runnable接口
    class MyRunnable implements Runnable {
        @Override
        public void run() {
            // do something
        }
    }
    
    Thread thread = new Thread(new MyRunnable());
    thread.start();
复制代码

三:线程的状态

  • 线程的状态标志
    public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
    }
复制代码
  1. NEW 线程刚刚创建,尚未启动
  2. RUNNABLE 线程正在运行
  3. BLOCKED 线程堵塞状态,等待同步块的锁的释放,如果获得锁,就会自动进入运行状态
  4. WAITING 线程处于等待状态,需要被其他线程唤醒(notify、notifyAll方法的调用)。线程在调用了join之后,也会进入等待状态,直到被join的线程执行结束才会被唤醒
  5. TIMED_WAITING 有限时间的等待,一般出现在调用sleep(time),join(time),sleep(time)后
  6. TERMINATED 线程运行结束
  • 线程的状态转换

四:线程的基本属性

private volatile String name; // 线程名称
private int         priority; // 优先级,1~10
private boolean     daemon = false; // 是否是守护线程
private Runnable target; // 实际被执行的对象
ThreadLocal.ThreadLocalMap threadLocals = null; // 当前线程的数据
private long tid; // 线程id
复制代码

五:线程创建初始化

    private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
        // 获取当前线程,给新创建的线程设置线程组
        Thread parent = currentThread();
        if (g == null) {
            g = parent.getThreadGroup();
        }
        // ThreadGroup nUnstartedThreads++;
        g.addUnstarted();
        this.group = g;

        this.target = target;
        this.priority = parent.getPriority(); // 使用父线程的优先级
        this.daemon = parent.isDaemon();  // 使用父线程的属性,是否是守护线程
        setName(name);

        init2(parent);

        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;
        tid = nextThreadID();
    }
复制代码

六:主要方法

    public synchronized void start() {
        // 判断状态,只能启动一次
        if (threadStatus != 0 || started)
            throw new IllegalThreadStateException();
        group.add(this);

        started = false;
        try {
            nativeCreate(this, stackSize, daemon);
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
    
    // 执行方法,target是实际可执行的Runnable对象
    public void run() {
        if (target != null) {
            target.run();
        }
    }
    
    // 退出
    private void exit() {
        // 将当前线程冲ThreadGroup里面移除
        if (group != null) {
            group.threadTerminated(this);
            group = null;
        }
        target = null;
        threadLocals = null;
        inheritableThreadLocals = null;
        inheritedAccessControlContext = null;
        blocker = null;
        uncaughtExceptionHandler = null;
    }
    
    // 线程中断
    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                nativeInterrupt();
                b.interrupt(this);
                return;
            }
        }
        nativeInterrupt();
    }
    
    public final void join(long millis) throws InterruptedException {
        synchronized(lock) {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                lock.wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                lock.wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
        }
    }
    
    public static native void yield();
复制代码

小结:

  1. 什么是守护线程?

守护线程与普通线程的唯一区别是:当JVM中所有的线程都是守护线程的时候,JVM就可以退出了;如果还有一个或以上的非守护线程则不会退出。(以上是针对正常退出,调用System.exit则必定会退出)

创建守护线程,thread.setDaemon(true);必须在start()之前调用。

参考:守护线程与普通线程

  1. ThreadLocal

  2. sleep
    sleep使当前线程暂停,并没有释放锁,经过传入的time时间后自动继续执行。

  3. yield
    暂停当前线程,让其它优先级大于等于该线程的线程有机会先执行,不过不能保证该线程能够立即停止。

  4. join
    当前线程暂停,等待插入的线程执行完毕之后继续执行。

  5. interrupt
    线程中断,只是设置了一个中断标志,在线程中用户自己获取这个标志然后自己退出。


参考: 【Java8源码分析】线程-Thread类的全面剖析

转载于:https://juejin.im/post/5bc96de9e51d450f0a5a31a5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值