专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java高并发编程-深入了解Thread类

temp10 2025-01-05 20:20:55 java教程 13 ℃ 0 评论

在上篇文章中我们提到在Thread构造函数中可以显式的指定线程名,其实在线程的构造函数中不但可以指定线程名,还可以指定线程组,也就是前面提到的参数中的ThreadGroup。在之前的分享中,我们提到一个概念,就是在调用了线程的构造方法之后,都会调用其中的一个init()方法。这里我们就从init()方法入手来进行分析。

Thread 与ThreadGroup

在init()方法中有如下的一段代码。

Java高并发编程-深入了解Thread类

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

通过上面代码,我们可以知道,如果在Thread构造函数中没有指定ThreadGroup,那么子线程就会被加入到父线程所在的线程组。通过如下的测试代码来看一下这其中的关系。

public class ThreadConstruction {
    public static void main(String[] args){
        Thread t1 = new Thread("T1");

        ThreadGroup group = new ThreadGroup("TestGroup");

        Thread t2 = new Thread(group,"T2");

        ThreadGroup mainThreadGroup = Thread.currentThread().getThreadGroup();

        System.out.println("主线程所属的线程组是:"+mainThreadGroup.getName());
        System.out.println("T1 线程和 主线程 是否属于同一组 "+(mainThreadGroup==t1.getThreadGroup()));
        System.out.println("T2 线程和 主线程 是否属于同一组 "+(mainThreadGroup==t2.getThreadGroup()));
        System.out.println("T2 线程和  group 是否属于同一组 "+(group==t2.getThreadGroup()));
    }
}

从上面代码可以看出,先创建了一个Thread t1 的线程,在创建了一个ThreadGroup对象,创建了一个Thread t2 的线程,并且将其加入到了group中。并没有给T1指定任何的group。执行上面的代码运行结果如下图所示。

从上面的结果,我们可以得到如下的几个结论

  • main函数所在的线程组被称为是主线程组
  • 构造线程的时候如果没有指定线程组,那么它的线程组与父线程同在同一个线程组。

在默认设置中,子线程和父线程都属于同一个线程组,并且还会与父线程拥有同样的优先级。这个会在后续的分享中进行详细的介绍。

Thread 和 StackSize的关系

在Thread的构造函数中,有一个被我们忽略的参数stackSize,这个参数到底是干什么用的,它对线程的影响到底是什么样的呢?,接下来就来看一下这个问题。

一般情况下,线程在创建的时候使用者其实并不会手动指定栈内存地址,而通过XSS参数进行设置。通过查找资料不难发现stackSize越大就表示正在线程内方法调用的递归深度就越大。stackSize越小则代表创建线程数越多。当然这个也是因平台而异的。

在有些平台下,将stack设置得越高,可以允许递归的深度就越深,反之,设置越低则表示,能够允许递归的深度就越浅。当然在某些平台下这些参数的设置根本就不起任何作用。只是给了开发者一个心理安慰,测试代码如下

public class ThreadConstruction {

    public static void main(String[] args) {
      
        ThreadGroup group = new ThreadGroup("TestGroup");
        
        Runnable runnable = new Runnable() {
            
            final int MAX = Integer.MAX_VALUE;
            @Override
            public void run() {
                int i = 0;
                recurse(i);
            }
            
            private void recurse(int i){
                System.out.println(i);
                if (i<MAX){
                    recurse(i+1);
                }
            }
        };
        
        Thread thread = new Thread(group,runnable,"Test",Integer.parseInt("1"));
        thread.start();
        
    }
}

Thread 与 虚拟机栈

我们之前了解过,在JVM内存中,程序计数器是一块比较小的内存空间,这个部分的内存不会出现任何溢出现象的。在所有内存空间区域中,与线程的创建、运行、销毁等一系列操作有关系的就是虚拟机栈内存了。栈内存的大小直接决定了JVM中可以被创建多少个线程。代码如下

public class ThreadCounter extends Thread {
    
    final static AtomicInteger counter = new AtomicInteger(0);

    public static void main(String[] args) {
        
        try {
            while (true){
                new ThreadCounter().start();
            }
        }catch (Throwable e){
            System.out.println("failed At => "+counter.get());
        }
    }

    @Override
    public void run() {
        try {
            System.out.println("The "+counter.getAndIncrement()+"thread be created.");
            TimeUnit.MINUTES.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

从代码中可以知道,我们一直创建线程移植到JVM不能在为线程分配空间为止。这样就可以测试出来栈内存空间大小对于线程分配的影响。

通过图表可以分析出来,线程数量与虚拟机栈空间大小的一种变化影响规律。

总结

在JVM中到底能创建多少线程,与堆内存、栈内存的大小有着直接的关系。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表