资讯专栏INFORMATION COLUMN

Thread源码阅读

isLishude / 720人阅读

摘要:中断状态可以通过来读取,并且可以通过一个名为的操作读取和清除。中断的协作特性所带来的一个好处是,它为安全地构造可取消活动提供更大的灵活性。中断允许一个可取消活动来清理正在进行的工作,恢复不变量,通知其他活动它要被取消,然后才终止。

Thread实现Runnable接口

1.Thread内部有个State枚举,标示着线程的状态。

NEW,新建未开始

RUNNABLE,可执行

BLOCKED,阻塞状态,等待一个monitor lock,或者Object.wait()之后重入一个synchronized锁定的代码

WAITING,等待状态,Object.wait(),Thread.join(),LockSupport.park()之后进入此状态

TIMED_WAITING,带超时时间的等待状态,Object.wait(long),Thread.join(long),LockSupport.parkNanos(),LockSupport.parkUntil()之后进入此状态

TERMINATED,终止状态

2.接着看下Thread的构造函数及其几个相关的成员变量
    /* 带目标run对象. */
    private Runnable target;

    /* 线程组 */
    private ThreadGroup group;
    
    /* 此线程的类加载器 */
    private ClassLoader contextClassLoader;
    
    /* 想要的栈大小,为0时此参数被忽略,且有VM不支持此参数 */
     private long stackSize;
     
    /* 状态标识,0代表新建未开始*/
    private volatile int threadStatus = 0;
    
    /* 静态native方法,返回当前线程*/
    public static native Thread currentThread();
 
 
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
     Thread(Runnable target, AccessControlContext acc) {
        init(null, target, "Thread-" + nextThreadNum(), 0, acc);
    }
     public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }
     public Thread(String name) {
        init(null, null, name, 0);
    }
    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }
    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }
    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }


    /**
     * Initializes a Thread.
     *
     * @param g 线程组
     * @param target 要执行的带run的目标对象
     * @param name 线程名
     * @param stackSize 新线程的栈大小,等于0时可忽略此参数
     * @param acc 接入控制上下文
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        //获取线程组
        if (g == null) {

            /* 从SecurityManager拿线程组  */
            if (security != null) {
                g = security.getThreadGroup();
            }

            /* 如果还没拿到从当前线程拿*/
            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);
        //从父线程继承可继承的ThreadLocal
        if (parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
      
        this.stackSize = stackSize;

        /* 设置线程ID */
        tid = nextThreadID();
    }

不同的构造函数很多,最终都调init方法,init主要实现的就是把相应的参数放入成员变量里,ThreadGroup的获取,接入控制,inheritableThreadLocals父继承,线程id自增。

3.调用线程执行的主方法start及run方法
/* 线程启动方法 */
 public synchronized void start() {
        /**
         * 如果线程不是NEW状态,则抛异常
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /*
        通知线程组此线程准备运行里,所以它可以加入到线程组列表中,线程组的未开始数量可以减少了 */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /*什么都不做,如果start0排除一个异常,它已经可以被调用栈知道 */
            }
        }
    }

    private native void start0();

start方法主要也是native实现,真正开始之前校验了状态,并接入ThreadGroup管理。

/* Runnale 接口的方法*/
   @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

真正的run其实是目标类的run方法

4.join方法,等待线程挂掉的方法,会抛出InterruptedException
/*如果这个线程还活着就一直等待*/
 public final void join() throws InterruptedException {
        join(0);
    }
/*如果这个线程还活着就一直等待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");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

Thread里为数不多的纯Java代码,它被synchronized标记,实现主要是自旋方法检验线程是否活着,如果活着,则wait释放锁,还有疑问请移步join的讨论

6.sleep方法,native实现,会抛出InterruptedException
/* 睡眠指定毫秒,并不释放monitor*/
 public static native void sleep(long millis) throws InterruptedException;
7.yield方法,native实现
/*使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了*/
    public static native void yield();
7.interrupt方法,更多关于中断的请见处理中断

每个线程都有一个与之相关联的 Boolean 属性,用于表示线程的中断状态(interrupted status)。中断状态初始时为 false;当另一个线程通过调用 Thread.interrupt() 中断一个线程时,会出现以下两种情况之一。如果那个线程在执行一个低级可中断阻塞方法,例如 Thread.sleep()、 Thread.join() 或 Object.wait(),那么它将取消阻塞并抛出 InterruptedException。否则, interrupt() 只是设置线程的中断状态。 在被中断线程中运行的代码以后可以轮询中断状态,看看它是否被请求停止正在做的事情。中断状态可以通过 Thread.isInterrupted() 来读取,并且可以通过一个名为 Thread.interrupted() 的操作读取和清除。
中断是一种协作机制。当一个线程中断另一个线程时,被中断的线程不一定要立即停止正在做的事情。相反,中断是礼貌地请求另一个线程在它愿意并且方便的时候停止它正在做的事情。有些方法,例如 Thread.sleep(),很认真地对待这样的请求,但每个方法不是一定要对中断作出响应。对于中断请求,不阻塞但是仍然要花较长时间执行的方法可以轮询中断状态,并在被中断的时候提前返回。 您可以随意忽略中断请求,但是这样做的话会影响响应。
中断的协作特性所带来的一个好处是,它为安全地构造可取消活动提供更大的灵活性。我们很少希望一个活动立即停止;如果活动在正在进行更新的时候被取消,那么程序数据结构可能处于不一致状态。中断允许一个可取消活动来清理正在进行的工作,恢复不变量,通知其他活动它要被取消,然后才终止。

    /* 
     * 这个对象的线程被可中断的I/O操作阻塞,这个blocker的interrupt方法应      * 该被设置完中断状态后触发
     */
    private volatile Interruptible blocker;
    private final Object blockerLock = new Object();

    /* 设置blocker; invoked via sun.misc.SharedSecrets from java.nio code
     */
    void blockedOn(Interruptible b) {
        synchronized (blockerLock) {
            blocker = b;
        }
    }
   public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            //如果被可中断IO阻塞,走此逻辑
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // 仅仅设置interrupt标识位
                b.interrupt(this);     
                return;
            }
        }
        interrupt0();
    }
    
    //当前线程是否被中断,并清空中断状态(连续两次调用,第二次一定返回false)
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
        }
    //当前线程是否被中,根据true,false来是否重置中断zhuangt
    private native boolean isInterrupted(boolean ClearInterrupted);
     
     //当前线程是否被中断,不修改中断状态
     public boolean isInterrupted() {
        return isInterrupted(false);
    } 

其它还有很多调试的方法activeCount,dumpStack就不讨论了

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70045.html

相关文章

  • LockSupport源码阅读

    摘要:源码阅读创建锁和同步类中使用的基础的线程阻塞原语除非你是多线程专家,而且你要自己设计和实现阻塞式线程同步机制比如等等,否则你不需要用和。 LockSupport源码阅读 /* * 创建锁和同步类中使用的基础的线程阻塞原语 * * 除非你是多线程专家,而且你要自己设计和实现阻塞式线程同步机制(比如lock、condition等等),否则你不需要用park和unpark。这两个原语是...

    CastlePeaK 评论0 收藏0
  • Junit源码阅读(四)之自定义扩展

    摘要:前言上次的博客中我们着重介绍了的机制,这次我们将聚焦到自定义扩展上来。在很多情形下我们需要在测试过程中加入一些自定义的动作,这些就需要对进行包装,为此提供了以接口和为基础的扩展机制。 前言 上次的博客中我们着重介绍了Junit的Validator机制,这次我们将聚焦到自定义扩展Rule上来。在很多情形下我们需要在测试过程中加入一些自定义的动作,这些就需要对statement进行包装,...

    Little_XM 评论0 收藏0
  • 深入理解Python中的ThreadLocal变量(中)

    摘要:在深入理解中的变量上中我们看到的引入,使得可以很方便地在多线程环境中使用局部变量。特别需要注意的是,基类的并不会屏蔽派生类中的创建。到此,整个源码核心部分已经理解的差不多了,只剩下用来执行清除工作。 在 深入理解Python中的ThreadLocal变量(上) 中我们看到 ThreadLocal 的引入,使得可以很方便地在多线程环境中使用局部变量。如此美妙的功能到底是怎样实现的?如果你...

    DataPipeline 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<