JAVA多线程(二)

2019-04-18  本文已影响0人  以南之南_b9a1

线程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,那么他会加入父线程所在的线程组,

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等特性。

上一篇下一篇

猜你喜欢

热点阅读