zoukankan      html  css  js  c++  java
  • 4.构造Thread对象你也许不知道的几件事

    1.Thread类对象只有在调用了start()方法之后,JVM虚拟机才会给我们创建一个真正的线程!否则就不能说是创建了线程!也就是说new Thread()之后,此时实际上在计算机底层,操作系统实际上并没有为我们创建线程!

    在我们new Thread();的时候,我们点击源码就可以看到:

        public Thread() {
            init(null, null, "Thread-" + nextThreadNum(), 0);
        }
    

    实际上是调用了init()方法,而且这个init()方法有几个参数,这里nextThreadNum()这个方法点进去就可以看到这是个静态方法,静 态方法只会在JVM启动的时候加载一次!

    那这几个参数又是什么意思呢?我们再点击去:

        private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize) {
            init(g, target, name, stackSize, null);
        }
    

    可以看到init方法的几个参数,第一个参数是线程组(传过来的是null),第二个参数是Runnable接口类对象,第三个参数是线程名称[从上一个init方法可以看出传递过来的名称是"Thread-数字"格式的名称],最后一个是栈的大小!然后在这个init()方法内部又调用了另一个重载的init()方法:如果此时再点就去就会看到如果线程组为null的话:

        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.toCharArray();
    
            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();
                }
            }
    

    如果线程组为null,那么它就就会将parent的线程组赋值给这个g,那么parent又是谁呢?parent是当前线程,如上所示:p= currentThread();也就是说如果传过来的线程组为空的话,那么它会将当前线程的线程组赋值给这个g线程组对象!如下代码验证:

    	public static void main(String[] args) {
    		//这种方式创建的线程,init方法默认传递给线程组g为null
    		Thread t = new Thread();
    		t.start();
    		//此时线程t的线程组实际上就是当前线程的线程组【当前线程也就是main线程,因为是main线程执行的这段代码】
    		System.out.println(t.getThreadGroup().getName());
    		System.out.println(Thread.currentThread().getName());
    	}
    

    上述代码说明:如果构造线程对象时未传入ThreadGroup,Thread会默认获取父线程的ThreadGroup作为该线程的ThreadGroup,也就是说此时:父线程和子线程会在同一个ThreadGroup中!另外,如果我们此时获取到了ThreadGroup,那么我们就可以通过这个ThreadGroup的API获取到这个ThreadGroup有多少个线程在运行!按正常情况

    来讲这里应该是有两个线程,那我们通过如下代码输出看一下:

    	public static void main(String[] args) {
    		//这种方式创建的线程,init方法默认传递给线程组g为null
    		Thread t = new Thread(){
    			@Override
    			public void run() {
    				try {
    					Thread.sleep(1000L);
    				} catch (InterruptedException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		};
    		t.start();
    		ThreadGroup group = t.getThreadGroup();
    		int count = group.activeCount();
    		//创建一个线程列表
    		Thread[] threads= new Thread[count];
    		//我们可以通过线程组的enumerate()方法将线程都放到这个线程列表中,便于我们查看!
    		group.enumerate(threads);
    		//System.out.println(group.activeCount());
    		for(Thread temp :threads){
    			System.out.println(temp);
    		}
    	}
    

    输出结果如下所示:

    Thread[main,5,main]
    Thread[Thread-0,5,main]
    

    注意:如果构造线程对象时没有传入ThreadGroup,Thread会默认获取父线程的ThreadGroup作为该线程的ThreadGroup,

         此时子线程和父线程将会在同一个ThreadGroup中

    那我们能不能在创建线程对象的时候,直接传入ThreadGroup类型的对象呢?当 然是可以的,以下四种构造函数:

    构造函数一:

        public Thread(ThreadGroup group, Runnable target) {
            init(group, target, "Thread-" + nextThreadNum(), 0);
        }
    

    构造函数二:

        public Thread(ThreadGroup group, String name) {
            init(group, null, name, 0);
        }
    

    构造函数三:

        public Thread(ThreadGroup group, Runnable target, String name) {
            init(group, target, name, 0);
        }
    

    构造函数四:  

        public Thread(ThreadGroup group, Runnable target, String name,
                      long stackSize) {
            init(group, target, name, stackSize);
        }
    

    至于ThreadGroup的知识点,我们这里先不展开讲,后面我们会给大家详细的讲解ThreadGroup这些知识!需要注意的是这里有个参数是stackSize,这个参数指的是栈大小,实际上也就是指虚拟机栈的大小!虚拟机栈是线程所私有的,也就是说每一个方法执行的时候都会创建一个栈帧放在虚拟机栈中!当JVM创建主线程(main线程)的时候就在内存中开辟了一块空间:虚拟机栈。

    需要注意的是:在内存中,堆的大小是比较大的【存对象和数组】,而栈的地址不怎么大,这里仅仅是存地址引用,所以比较小! 

     总结1:构造函数new Thread();  创建线程对象Thread,默认有一个线程名,都是以Thread-开头,从0开始!形如:

         Thread-0 Thread-1 Thread-2 Thread-3等! 而且这种构造方法的target会被传递为null!也就是用这个构造

         方法时最终Runnable类型的target对象会被设置为null!此时再看源码就可以知道如果target被设置为null,那

           么start()方法在调用start0()方法,而start0()方法在调用run()方法的时候就不会再调用Runnable实现类的run()

        方法,那么此时如果不调用target对象的run方法,我们此时就要自己重写这个Thread类 的run方法了,此时

           调用Thread类对象的start方法,才会执行我们自己写的run方法,如果我们自己此时也不重写Thread类的run

           方法,那么什么也不会执行!

    总结2:当然我们也可以使用Thread(String name)这个构造函数给线程对象起一个名子!

    总结3:我们可以通过Thread(Runnable target, String name)这个构造函数在创建Thread对象的时候给Thread传递一个

            Runnable接口实现类对象和线程名!

  • 相关阅读:
    本地邮件系统的安装及配置
    通用性站点管理后台(Bee OPOA Platform) (2) 快速开发特性
    (转).NET Framework 自动内存管理机制深入剖析 (C#分析篇)
    通用性站点管理后台(Bee OPOA Platform) (3) MVC特性
    通用性站点管理后台(Bee OPOA Platform) (4) DAL
    通用性站点管理后台(Bee OPOA Platform) (1)
    【讨论】一个接口的世界
    Ubuntu Mono 初体验
    发现assembly的dll在temp里,AppDomain无法动态加载那个assembly
    熟知android模拟器的快捷键
  • 原文地址:https://www.cnblogs.com/python-machine/p/7257006.html
Copyright © 2011-2022 走看看