【Java Thread StackSize】如何理解Java中Thread构造器中的stackSize的默认值为0?

2 篇文章 0 订阅
1 篇文章 0 订阅

                    Thred的stackSize默认值

                                                     e-mail:rolltion.zhang@foxmail.com

 

前言:为什么要研究默认值

在Java和Java开发框架中,我们经常会遇到一系列的默认值,尽管他们种类繁多、功能不同,但他们在程序中扮演着举足轻重,至关重要的角色。

默认值,也作缺省值,即在用户(广义用户)不传入特定参数的情况下也有一个默认的值作为该参数的值,一般具有默认值的参数都有极高的特异性,也就是说,这个参数在程序中也许起着画龙点睛的作用,研究默认值有利于我们理解程序设计理念、运行机制、功能特性等。

一.Thread的构造器

 Thread相信大家都经常使用,不陌生,研读过阿里巴巴的《阿里巴巴Java开发手册(终极版)》的同学应该都注意到,在其规范的“”并发”编程中,规定了不能显式地创建线程,只能通过创建线程池来管理线程,其目的是利用池化思想合理利用资源,但归根结底是通过实现ThradFactory接口创建,其中的方法使用了显式的构造器创建线程,以下是Thread类的9个public的构造器:

    //构造器1
    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }
    
    //2
     public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }
    //3
    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }
    //4
    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }
    //5
       public Thread(String name) {
        init(null, null, name, 0);
    }
    //6
        public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }
    //7
        Thread(Runnable target, AccessControlContext acc) {
        init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
    }
    //8
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    //9
     public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

 从上面的构造器我们不难看出,无论是有参数构造器还是无参构造器,最后都是指向init方法的,init的方法最后指向同名私有方法:

 

/**
     * Creates a new Thread that inherits the given AccessControlContext.
     * This is not a public constructor.
     */
    Thread(Runnable target, AccessControlContext acc) {
        init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
    }

 从Thread构造器中可以看出,未指定stackSize的构造器的值,即默认值都是0

二.什么是StatckSize?

要理解这问题,我们需要先了解什么是Java的虚拟机栈,JVM的架构是基于虚拟机栈的,它是一种可被用来快速访问的存储空间,一般位于RAM里,其速度仅次于寄存器,栈的核心是“栈指针”,指针下移则分配新的内存,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据在多个线程或者多个栈之间是不可以共享的,但是在栈内部多个值相等的变量是可以指向一个地址的。

关于栈不理解的可以查看:https://www.tuicool.com/articles/URZrMnb

因此,这就导致了一个问题,JVM在运行java程序时,需要预先知道被存储在栈内的数据的确切大小、生命周期等信息,这时我们就说开辟了栈空间,即stack size,如果超过了栈的最大深度,就会出现StackOverflowError。

在这个内存开辟的过程中,我们不得不提到一个 名词“操作数栈”,操作数栈也常被称为操作栈,它是一个后入先出栈。同局部变量表一样,操作数栈的最大深度也是编译的时候被写入到方法表的Code属性的 max_stacks数据项中。操作数栈的每一个元素可以是任意Java数据类型,包括long和double。32位数据类型所占的栈容量为1,64位 数据类型所占的栈容量为2。栈容量的单位为“字宽”,对于32位虚拟机来说,一个”字宽“占4个字节,对于64位虚拟机来说,一个”字宽“占8个字节。

例如我们可以写一段代码来测试一下,jvm的默认栈深度:

public class TestStack{
private int counter=0;
    private void recur(){
        counter++;
        recur();//递归
    }
    public void getStackDepth(){
        try {
            recur();
        }catch (Throwable t){
            System.out.println("栈最大深度:"+counter);
            t.printStackTrace();
        }
        
    }
    
public static void main(String[] args){
    TestStack stack=new TestStack();
    stack.getStackDepth();
        
    }


}

通过上面的例子我们可以看出,在实际的代码运行中,我们需要为线程开辟特定的栈空间,那Thread为什么要指定这个值为0呢?为0不就是不开辟空间了么?

三.为什么stacksize的默认值是0

/*
     * 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;

stackSize是Thread类的局部变量,官方给出的解释是:当前线程的指定栈大小,如果线程的创建者不指定大小,那默认值就是0,对这个书如何进行操作取决于JVM,有些JVM会忽略掉这个参数。

因此,设置这个参数以及这个参数是否生效取决于平台,和实际生产需要,如果设置了更小的栈深度,JVM能支持同时存活更多的线程,反之,单个线程拥有更大的递归深度,但是带来的是支持更少线程同时存活,因为我们的栈空间是一定的。

那么就有人问了,如果我故意把值设置的很高或者很低,那会怎么样呢?

事实是这样的:

 

如果没有特殊的需求,尽量不要修改此参数,因为它本身的作用和范围取决于平台,在不同的VM上使用此参数,跨平台迁移时,如果以前已设定了对应值,需要检查是否需要修改这个参数。

以上。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值