美文网首页
当new Thread,以及调用start、join等操作时,到

当new Thread,以及调用start、join等操作时,到

作者: 柚子过来 | 来源:发表于2018-06-15 10:45 被阅读0次

    首先看看Thread中定义了哪些常见的变量域:

    public class Thread implements Runnable {        //Thread实现自Runable
    /* Make sure registerNatives is the first thing <clinit> does. */
    private static native void registerNatives();
    static {
        registerNatives();
    }
    
    private volatile String name;                              //线程名
    private int            priority;                                  //线程优先级
    
    /* Whether or not the thread is a daemon thread. */
    private boolean     daemon = false;                 //是否是守护线程
    
    /* What will be run. */
    private Runnable target;                                //线程体Runable
    
    /* The group of this thread */
    private ThreadGroup group;                         //线程组
    
    /* The context ClassLoader for this thread */
    private ClassLoader contextClassLoader;
    
    /* For autonumbering anonymous threads. */
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }
    
    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;           //ThreadLocalMap 
    
    /*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;     //可继承的ThreadLocalMap 
    
    /*
     * The requested stack size for this thread, or 0 if the creator did
     * not specify a stack size.  It is up to the VM to do whatever it
     * likes with this number; some VMs will ignore it.
     */
    private long stackSize;                 //线程栈大小
    
    /*
     * Thread ID
     */
    private long tid;
    
    /* For generating thread ID */
    private static long threadSeqNumber;
    
    /*
     * Java thread status for tools, default indicates thread 'not yet started'
     */
    private volatile int threadStatus;     //线程状态:NEW-0,RUNNABLE,BLOCKED、WAITING、TERMINATED
    

    当我们new Thread(Runable runable)的时候,调用的构造函数是这样的:

     public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    
     public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }
    
     public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }
    

    可以看到除了传入Runable,我们还可以指定线程所在组、线程栈的大小等,看看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();
        if (g == null) {                             //设置了线程所在组
            /* Determine if it's an applet or not */
            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) {
                g = security.getThreadGroup();
            }
            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) {
                g = parent.getThreadGroup();      //继承父线程的线程组,所以所有启动的线程都是放在同一个线程组main中
            }
        }
        ... ...
        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.target = target;
        setPriority(priority);
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =                  //继承父线程的inheritableThreadLocals 
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;        //设置线程栈大小
    
        /* Set thread ID */
        tid = nextThreadID();       //递增生成线程id
    }
     private static synchronized long nextThreadID() {
        return ++threadSeqNumber;
    }
    

    新建了一个线程之后,线程状态是NEW,这时候我们可以调用start启动线程,这时候做了什么:

      public synchronized void start() {
    
        if (threadStatus != 0)         //只有NEW状态的线程在可以start,不然会抛异常
            throw new IllegalThreadStateException();
    
        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);                  //线程启动后才会被加入线程组
    
        boolean started = false;
        try {
            start0();                          //调用本地方法启动线程
            started = true;
        } finally {
           ... ...
        }
    }
    
    private native void start0();
    

    如果我们再调用join方法呢:

     public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
         ... ...
        if (millis == 0) {
            while (isAlive()) {         //会阻塞其他所有线程直到当前线程执行完毕
                wait(0);
            }
        } else {
            while (isAlive()) {
               ... ...
            }
        }
    }
    

    想要中断线程可以使用interrupt,其他的像stop、destroy方法在最新的jdk中将被废弃移除:

       public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();
    
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }
    

    但是注意该方法只是设置了中断标志位,并不是直接中止线程,这时有两种情况:1、线程处于阻塞状态,这时会抛出中断异常。2、线程处于非阻塞状态,那JVM会在"合适的时机"终止线程,我们可以在程序中使用while(isInterrupted)来进行判断进而进行相关处理

    还有其他的像getStackTrace()获取线程栈信息、yield()让出CPU重新进入就绪状态等

    前面提到线程的各个状态,那哪些操作会影响线程的状态呢:

    1、start、join、yield等线程自身的方法
    2、Object类的wait/notify/notifyAll方法
    3、并发库中的工具,如闭锁、栅栏
    4、获取锁操作导致的阻塞
    ... ...

    相关文章

      网友评论

          本文标题:当new Thread,以及调用start、join等操作时,到

          本文链接:https://www.haomeiwen.com/subject/lyjpeftx.html