美文网首页
JAVA多线程(二)

JAVA多线程(二)

作者: 以南之南_b9a1 | 来源:发表于2019-04-18 21:47 被阅读0次

    线程Thread API分析


    线程API

    我们在创建线程的时候 建议同时需要给当前线程起一个名字,为线程赋予一个有意义的名字,有助于我们排查问题,

    线程的默认命名

    Thread();
    Thread(Runnable target);
    Thread(ThreadGroup group,Runnable target);
    
     private static int threadInitNumber;
     private static synchronized int nextThreadNum() {
         return threadInitNumber++;
     }
     public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
        }
    

    我们有Thread.java类看出 如果我们没有给当前线程命名,那么线程将会以"Thread-"作为前缀与一个数字进行组合,这个自增的数字在整个JVM进程会不断增加。

    那么,我们需要给当前线程命名:

    Thread(Runnable target,String name);
    Thread(String name);
    Thread(ThreadGroup threadGroup,Runnable runnable,String name);
    Thread(ThreadGroup threadGroup,Runnable runnable,String name,long stackSize);
    Thread(ThreadGroup group,String name);
    
    //给当前thread命名
    public final synchronized void setName(String name) {
            checkAccess();
            if (name == null) {
                throw new NullPointerException("name cannot be null");
            }
    
            this.name = name;
            if (threadStatus != 0) {//如果线程不是new状态 则不会执行下面代码
                setNativeName(name);
            }
        }
    

    不论你使用的是默认的名字,还是自定义名字,如果一个线程启动,那么线程的名字,将不能被修改。从源代码可以看出。

    线程的父子关系

    Thread的所有构造函数,都会去执行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();
                }
            }
    
            /* checkAccess regardless of whether or not threadgroup is
               explicitly passed in. */
            g.checkAccess();
    
            /*
             * Do we have the required permissions?
             */
            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)
                this.inheritableThreadLocals =
                    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
            /* Stash the specified stack size in case the VM cares */
            this.stackSize = stackSize;
    
            /* Set thread ID */
            tid = nextThreadID();
        }
    

    有上述代码可以看出来 currentThread() 是获取当前线程,我们new出Thread ,没有执行start之前,他只能代表当前线程的一个事例,由此我们可以推出,currentThread()方法得到的应该是父线程。

    • 一个线程肯定是由另一个线程创建的。
    • 被创建的线程肯定是它的父线程。
    ThreadGroup 和Thread

    在构造Thread的时候,可以显式的将当前线程加入一个线程组中,如果在构造Thread的时候并没有显式的指定一个ThreadGroup,那么他会加入父线程所在的线程组,

    • main线程所在的ThreadGroup称为main

    Thread和Runnable

    Thread负责线程本身的职责相关和控制,而Runnable则负责逻辑单元的部分。符合类的单一职责原则。

    堆内存不变,栈内存越大,可创建的线程数量越小
    占内存不变,堆内存越大,可创建的线程数量越小
    线程数量=(最大地址空间-JVM堆内存-ReservedOsMemory)/ThreadStackSize(Xss);

    守护线程

    概念:守护线程是一个特殊的线程,一般用于后台处理工作,
    特点:调用setDaemon方法即可,true代表守护线程,如果父线程是守护线程,则子线程也是正常线程,setDaemon只有在线程启动之前设置才能生效,
    作用:如果JVM没有一个非守护线程,那么JVM会退出,非守护线程没有生命周期,如果main方法完成了工作,则JVM无法退出,因为还有守护线程(垃圾回收线程还在工作)。

    public void main(String [] args){ 
        Thread thread = new Thread(){
           while(true){
               sleep(1);
           }
        }
    }
    thread.setDaemon(true);
    thread.start();
    Thread.sleep(200);
    System.out.println("main threadLife  end ");
    

    总结
    我们了解了Thread的构造函数,也介绍了线程的父子关系,以及总父线程哪里继承了优先级,守护线程,和ThreadGroup等特性。

    相关文章

      网友评论

          本文标题:JAVA多线程(二)

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