继续学习一下Thread的构造函数,在上次【http://www.cnblogs.com/webor2006/p/7760422.html】已经对如下构造都已经学习过了:
![](https://img-blog.csdnimg.cn/img_convert/7c2e3f65f590e8504a7e1c5d5adf2339.png)
多线程与JVM内存结构的关系【了解】:
对于最后一个有疑问的构造中stackSize参数,其实学过编程滴人从参数字面就比较容易理解,栈大小嘛,这里从官方文档上来了解一下这个参数:
![](https://img-blog.csdnimg.cn/img_convert/e781745c6d3f8f77e239d932ed7d7773.png)
而之前在学习java的时候基本上都是把jvm内存结构简单理解成一个栈区、一个堆区,其实要更好的理解这个stackSize,其实需要更细致的了解一下jvm的内存结构,所以在动手做实验之前先来把理论夯实下基础更细致的了解一下JVM内存结构,下面以图的方式来展开:
还是从我们耳濡目染的堆栈大类开始:
![](https://img-blog.csdnimg.cn/img_convert/498a368f6488726657af8d51bb0478f3.png)
不多解释,下面来慢慢细化它里面的内容:
![](https://img-blog.csdnimg.cn/img_convert/0dcc7ac0cad7e0d99ab4010c4b11ee84.png)
其中这部分区域是线程共享的区域,对应代码理解:
![](https://img-blog.csdnimg.cn/img_convert/3cd88a893ea862b2de1c3ddb01b44c4f.png)
![](https://img-blog.csdnimg.cn/img_convert/7de130a07d8a53d1212dd93a94e02c71.png)
![](https://img-blog.csdnimg.cn/img_convert/b5b7cc62fa60cd292d7934edf53fcd6d.png)
继续细化:
![](https://img-blog.csdnimg.cn/img_convert/3e7fbae2b1f6746796f3cbcfdecc0932.png)
继续细化:
![](https://img-blog.csdnimg.cn/img_convert/16724ae1568a978b2cf6d5560860d35c.png)
接着就要引来重点讨论的区域了【上图中故意在栈区上留了一个空缺就是用来说明它滴~~】:
![](https://img-blog.csdnimg.cn/img_convert/f3337ebce58b3a0dfc88e2f7a4833642.png)
那虚拟机栈里面存放的是什么东东呢?其实它是存放每一个线程私有的东东,而每一个方法执行的时候都会存放一个栈帧,也就是虚拟机栈中存放的就是一个个栈帧,那栈帧里面存放的是啥东东呢?
![](https://img-blog.csdnimg.cn/img_convert/986476eed8134f527ca2ca909a195e16.png)
![](https://img-blog.csdnimg.cn/img_convert/79b74a0a1bf7f1086addaa0d339633f5.png)
下面再来对照代码来理解:
![](https://img-blog.csdnimg.cn/img_convert/fbbbf58d89c5e2274596cbd4f3919022.png)
而对于线程中会有执行native方法:
![](https://img-blog.csdnimg.cn/img_convert/0f62b89d5f220baa35185c446cc162f2.png)
所以它就存放在本地方法区,如下:
![](https://img-blog.csdnimg.cn/img_convert/580a849d61474f267d83d236152542a7.png)
而在执行了main函数就会创建一个栈帧,这里在main函数中定义一个变量,如下:
![](https://img-blog.csdnimg.cn/img_convert/696426be6479e25af6eb3a5f0529bfc7.png)
也就是它:
![](https://img-blog.csdnimg.cn/img_convert/289465d73b33c69ffb04b3da05b8da9c.png)
说了这么多理论其实就是为了理解虚拟机栈的概念,对于JVM的内存结构不用太过纠结,说实话实在太抽象了,重点是为了理解虚拟机栈,因为Thread的构造中的StackSize就是针对它而存在的,有了这些理论之后准备做一个比较关键的实验啦,但是在做实验之前还得强调一个概念,如下:
![](https://img-blog.csdnimg.cn/img_convert/c9f66282f7e3fcf93a03112a478c49d7.png)
那下面做如下实验:
![](https://img-blog.csdnimg.cn/img_convert/d07c51b97d63d4487384822f143fcd5e.png)
从内存角度来分析一下代码:很明显只有递归调用,没有方法返回,也就是从栈帧中的"操作栈"来说,只有入栈,并没有出栈,而每调用一个方法就会在虚拟机栈中创建一个栈帧,那实际上会撑爆虚拟机栈,很明显这个程序会报我们实际开发中比较常见的error啦,如下:
![](https://img-blog.csdnimg.cn/img_convert/13496b300958bf7e8849ec97c4c41757.png)
那有了这个实验跟Thread的stackSize参数有啥关系么?当然有,而且关系是大大滴,下面就来回到正题来探究下Thread构造函数stackSize的作用吧。
Thread构造函数StackSize的使用:
先再来看下JDK对它的介绍:
![](https://img-blog.csdnimg.cn/img_convert/85fcbb26149cb6cd1a568ff98f53e030.png)
而刚才我们在main函数中去执行的递归由于是在JVM创建的main线程中执行的,那也就是无法咱们自己来定义这个stackSize,那将这个调用放到咱们自己定义的线程中呢,如下:
![](https://img-blog.csdnimg.cn/img_convert/0525e62dca8c36933b459cfde1ca659f.png)
![](https://img-blog.csdnimg.cn/img_convert/45764721c1c1ae703776f38f92c31b60.png)
那这时我们尝试去改变这个栈的大小:
![](https://img-blog.csdnimg.cn/img_convert/d47b30642924985dbf5199e20d6ea7b5.png)
![](https://img-blog.csdnimg.cn/img_convert/3c47c450de66247628d33358c7c2d142.png)
目前程序是运行的mac上的,说明在mac平台上给thread传stackSize是能起到一定的作用的,所以关于Thread的这个构造就了解了。
最后再来思考一下,如果不给Thread传stackSize,那它的栈大写是多少呢,查看一下源码:
![](https://img-blog.csdnimg.cn/img_convert/a50334b991cdeb429d2136df8e0eeef7.png)
![](https://img-blog.csdnimg.cn/img_convert/debd7be1f4e076bc6107bb569b3af746.png)
![](https://img-blog.csdnimg.cn/img_convert/dd009313e73f5bc13bed718d4234c1a7.png)
![](https://img-blog.csdnimg.cn/img_convert/fe9b58ad2d4ea3b31f01b22db105f301.png)
而奇怪的是这个参数并没有被Thread中的类似地方使用到它,所以有可能是被底层c++给使用了。
所以对于Thread这个stackSize可以进行如下总结:
构造Thread的时候传入stackSize代表着该线程占用的stack大小,如果没有指定stackSize的大小,默认是0,0代表着会忽略该参数,该参数会被JNI函数去使用,另外一个需要注意:该参数在一些平台有效,在有些平台则无效,所以平常要去设置stackSize一般通过jvm的参数-Xss10M(将虚拟机栈的大小写设置为10M),而不去通过线程的这个stackSize。