Tomcat部署

1.JVM介绍

JVM是Java Virtual Machine(Java虚拟机)的缩写

Java虚拟机本质是就是一个程序,当它在命令行上启动的时候,就开始执行保存在某字节码文件中的指令。Java语言的可移植性正是建立在Java虚拟机的基础上。任何平台只要装有针对于该平台的Java虚拟机,字节码文件(.class)就可以在该平台上运行。这就是“一次编译,多次运行”。

2.Tomcat介绍

a.什么是Tomcat

Tomcat和我们此前学习的 Nginx 类似,也是一个Web服务器。

b.Tomcat与Nginx有什么区别?

Nginx仅支持静态资源,而Tomcat则支持Java开发的 jsp 动态资源和静态资源。
Nginx适合做前端负载均衡,而Tomcat适合做后端应用服务处理。
通常情况下,企业会使用 Nginx+tomcat 结合使用,由Nginx处理静态资源,Tomcat处理动态资源。

3.Tomcat快速安装

方法1:

rpm -ivh jdk-8u102-linux-x64.rpm
mkdir /app
tar xf apache-tomcat-8.0.27.tar.gz -C /app
/app/apache-tomcat-8.0.27/bin/startup.sh 

方法2:

mkdir /app/
tar xf jdk-8u60-linux-x64.tar.gz -C /app/
ln -s /app/jdk1.8.0_60 /app/jdk
sed -i.ori '$a export JAVA_HOME=/app/jdk\nexport PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH\nexport CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar' /etc/profile
source /etc/profile
tar xf apache-tomcat-8.0.27.tar.gz -C /app
/app/apache-tomcat-8.0.27/bin/startup.sh 

4.Tomcat启动慢解决方案

没优化之前启动时间
[root@tomcat logs]# grep 'Server startup' catalina.out
03-Aug-2019 03:15:18.225 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 591050 ms

优化之后启动时间
[root@tomcat logs]# grep 'Server startup' catalina.out
03-Aug-2019 03:15:18.225 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 591050 ms
03-Aug-2019 03:22:14.112 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1326 ms

优化方法:
vi /usr/java/jdk1.8.0_102/jre/lib/security/java.security
securerandom.source=file:/dev/urandom

5.tomcat目录结构介绍

[root@tomcat apache-tomcat-8.0.27]# ll
total 92
drwxr-xr-x 2 root root  4096 Aug  3 03:05 bin  #主要包含启动、关闭tomcat脚本和脚本依赖文件
drwxr-xr-x 3 root root   198 Aug  3 03:05 conf #tomcat配置文件目录
drwxr-xr-x 2 root root  4096 Aug  3 03:05 lib  #tomcat运行需要加载的jar包
-rw-r--r-- 1 root root 57011 Sep 28  2015 LICENSE #license文件,不重要
drwxr-xr-x 2 root root   197 Aug  3 03:15 logs  #在运行过程中产生的日志文件
-rw-r--r-- 1 root root  1444 Sep 28  2015 NOTICE #不重要
-rw-r--r-- 1 root root  6741 Sep 28  2015 RELEASE-NOTES #版本特性,不重要
-rw-r--r-- 1 root root 16204 Sep 28  2015 RUNNING.txt   #帮助文件,不重要
drwxr-xr-x 2 root root    30 Aug  3 03:05 temp    #存放临时文件
drwxr-xr-x 7 root root    81 Sep 28  2015 webapps #站点目录
drwxr-xr-x 3 root root    22 Aug  3 03:05 work    #tomcat运行时产生的缓存文件

6.tomcat配置文件

https://blog.csdn.net/yes_is_ok/article/details/82992429

#多站点配置文件
vim /app/apache-tomcat-8.0.27/conf/server.xml
查找host 并复制 去除注释的字段
cp -a /app/apache-tomcat-8.0.27/webappas/*  /app/apache-tomcat-8.0.27/webappas2

7.Tomcat部署zrlog

上传代码加启动

8.配置tomcat basic认证

vim /app/apache-tomcat-8.0.27/webapps/ROOT/WEB-INF/web.xml
<web-app>
......    
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>test</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        
        <auth-constraint>
            <role-name>test100</role-name>
        </auth-constraint>
    </security-constraint> 
    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>Default</realm-name>
    </login-config>
</web-app>
# 添加系统角色
vim /app/apache-tomcat-8.0.27/conf/tomcat-users.xml
<role rolename="manager-gui"/>
<role rolename="test100"/>
<user username="tomcat" password="123456" roles="manager-gui,test100"/>
#重启tomcat生效

9.tomcat https配置文件

vim /etc/nginx/nginx.conf

worker_processes 1;
events {
  worker_connections 1024;
}

http {
  include mime.types;
  default_type application/octet-stream;
  sendfile on;
worker_processes 1;
events {
  worker_connections 1024;
}

http {
  include mime.types;
  default_type application/octet-stream;
  sendfile on;
  keepalive_timeout 65;
  upstream tom {
    server 10.0.0.7:8080;
    server 10.0.0.41:8080;
  }
  server {
    listen 443 ssl;
    server_name blog.oldqiang.com;
    ssl_certificate /root/ssl_key/Nginx/1_blog.oldqiang.com_bundle.crt;
    ssl_certificate_key /root/ssl_key/Nginx/2_blog.oldqiang.com.key;

    location / {
        proxy_pass http://tom;
        proxy_set_header Host $http_host;
    }
  }
  server {
    listen 80;
    server_name blog.oldqiang.com;
  return 302 https://$server_name$request_uri;
  }
}  

10.tomcat 实现读写分离

worker_processes 1;
events {
  worker_connections 1024;
}

http {
  include mime.types;
  default_type application/octet-stream;
  sendfile on;
  keepalive_timeout 65;
  upstream tom {
    server 10.0.0.7:8080;
    server 10.0.0.41:8080;
  }
  upstream tom2{
      server 10.0.0.7:8080;
  }
  server {
    listen 443 ssl;
    server_name blog.oldqiang.com;
    ssl_certificate /root/ssl_key/Nginx/1_blog.oldqiang.com_bundle.crt;
    ssl_certificate_key /root/ssl_key/Nginx/2_blog.oldqiang.com.key;

    location / {
        proxy_set_header Host $http_host;
#读写分离判断
        if ( $request_method = POST ){
        proxy_pass http://tom2;
     }
        proxy_pass http://tom;
    }
  #动静分离
  location ~.*\.(png|jpg) {
             root /data;
  }
  }
  server {
    listen 80;
    server_name blog.oldqiang.com;
  return 302 https://$server_name$request_uri;
  }
}

11.使用maven编译java项目

1.安装maven,二进制

下载maven

wget http://192.168.13.120/191118/apache-maven-3.6.1-bin.tar.gz

解压
tar xf apache-maven-3.6.1-bin.tar.gz -C /usr/local
ln -s /usr/local/apache-maven-3.6.1/ /usr/local/maven

给maven配置环境变量

vim /etc/profile
...
export M2_HOME=/usr/local/maven
export PATH=${M2_HOME}/bin:$PATH
source /etc/profile</pre>

2: java项目的源码

wget http://192.168.13.120/191118/SpringBootWeb.tar.gz
tar xf  SpringBootWeb.tar.gz

SpringBoot java开发框架

3:使用maven编译打包

cd  SpringBootWeb
​
maven源加速:
vim /usr/local/maven/conf/settings.xml
 <mirror>
 <id>alimaven</id>
 <name>aliyun maven</name>
 <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
 <mirrorOf>central</mirrorOf>
 </mirror>
​
mvn clean package  先清理缓存文件,再打包
​
mvn package 打包</pre>

4:部署war包

cp target/SpringBootWeb.war /app/apache-tomcat-8.0.27/webapps2/

5: 测试访问

浏览器访问:http://session.oldqiang.com/SpringBootWeb/

12.tomcat监控自定义

客户端
vim /application/apache-tomcat-8.0.27/bin/catalina.sh
CATALINA_OPTS="$CATALINA_OPTS
-Dcom.sun.management.jmxremote
-Djava.rmi.server.hostname=10.0.0.100
-Dcom.sun.management.jmxremote.port=12345
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false"

重启tomcat服务

zabbix 端
#安装zabbix-java-gateway 
yum install zabbix-java-gateway.x86_64  -y 
#配置zabbix-server和zabbix-java-gateway 
vim /etc/zabbix/zabbix_java_gateway.conf 
START_POLLERS=5
 
vim  /etc/zabbix/zabbix_server.conf 
JavaGateway=127.0.0.1 
JavaGatewayPort=10052 
StartJavaPollers=5
 
#启动服务 
systemctl restart zabbix-java-gateway.service 
systemctl restart zabbix-server.service 

13.tomcat调优化

#调优配置解释
[https://oldqiang.com/archives/435.html](https://oldqiang.com/archives/435.html)
请看一下一个时间的Java参数配置:(服务器:Linux 64Bit,8Core×16G)

JAVA_OPTS="$JAVA_OPTS -server -Xms3G -Xmx3G -Xss256k -XX:PermSize=128m -XX:MaxPermSize=128m -XX:+UseParallelOldGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/aaa/dump -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/usr/aaa/dump/heap_trace.txt -XX:NewSize=1G -XX:MaxNewSize=1G"
1.  ## 参数说明

-server -Xmx3g -Xms3g -XX:MaxPermSize=128m 

-XX:NewRatio=2                 # eden/old 的比例 

-XX:SurvivorRatio=8             # s/e的比例 

-XX:+UseParallelGC 

-XX:ParallelGCThreads=8 

-XX:+UseParallelOldGC             # 这个是JAVA 6出现的参数选项 

-XX:LargePageSizeInBytes=128m     # 内存页的大小, 不可设置过大,会影响Perm的大小 

-XX:+UseFastAccessorMethods     # 原始类型的快速优化 

-XX:+DisableExplicitGC         # 关闭System.gc() 

-Xss                                 # 是线程栈的大小 

另外 -Xss 是线程栈的大小,  这个参数需要严格的测试,一般小的应用,如果栈不是很深,  应该是128k够用的,不过,我们的应用调用深度比较大,还需要做详细的测试。这个选项对性能的影响比较大。**建议使用****256K****的大小**。 

1.  ## 常见配置汇总

    1.  ### 堆设置

**-Xms**:初始堆大小 

**-Xmx**:最大堆大小 

**-XX:NewSize=n**:设置年轻代大小 

**-XX:NewRatio=n**:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4 

**-XX:SurvivorRatio=n**:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5 

**-XX:MaxPermSize=n**:设置持久代大小 

1.  ### 收集器设置

**-XX:+UseSerialGC**:设置串行收集器 

**-XX:+UseParallelGC**:设置并行收集器 

**-XX:+UseParalledlOldGC**:设置并行年老代收集器 

**-XX:+UseConcMarkSweepGC**:设置并发收集器 

1.  ### 垃圾回收统计信息

**-XX:+PrintGC** 

**-XX:+PrintGCDetails** 

**-XX:+PrintGCTimeStamps** 

**-Xloggc:filename** 

1.  ### 并行收集器设置

**-XX:ParallelGCThreads=n**:设置并行收集器收集时使用的CPU数。并行收集线程数。 

**-XX:MaxGCPauseMillis=n**:设置并行收集最大暂停时间 

**-XX:GCTimeRatio=n**:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n) 

1.  ### 并发收集器设置

**-XX:+CMSIncrementalMode**:设置为增量模式。适用于单CPU情况。 

**-XX:ParallelGCThreads=n**:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。 

1.  ## 调优方法

一切都是为了这一步,**调优**,在调优之前,我们需要记住下面的**原则**: 

1、多数的Java应用不需要在服务器上进行GC优化; 

2、多数导致GC问题的Java应用,都不是因为我们参数设置错误,而是代码问题; 

3、在应用上线之前,先考虑将机器的JVM参数设置到最优(最适合); 

4、减少创建对象的数量; 

5、减少使用全局变量和大对象; 

6、GC优化是到最后不得已才采用的手段; 

7、在实际使用中,分析GC情况优化代码比优化GC参数要多得多; 

GC优化的目的有两个([](http://www.360doc.com/content/13/0305/10/15643_269388816.shtml)[http://www.360doc.com/content/13/0305/10/15643_269388816.shtml ):](http://www.360doc.com/content/13/0305/10/15643_269388816.shtml) 

 [**1、将转移到老年代的对象数量降低到最小;** 

**2、减少full GC的执行时间;** 

为了达到上面的目的,一般地,你需要做的事情有: 

1、减少使用全局变量和大对象; 

2、调整新生代的大小到最合适; 

3、设置老年代的大小为最合适; 

4、选择合适的GC收集器; 

在上面的4条方法中,用了几个"合适",那究竟什么才算合适,一般的,请参考上面"收集器搭配"和"启动内存分配"两节中的建议。但这些建议不是万能的,需要根据您的机器和应用情况进行发展和变化,实际操作中,可以将两台机器分别设置成不同的GC参数,并且进行对比,选用那些确实提高了性能或减少了GC时间的参数。 

真正熟练的使用GC调优,是建立在多次进行GC监控和调优的实战经验上的,进行监控和调优的一般步骤为: 

1.  **监控GC的状态** 

使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和gc日志,根据实际的各区域内存划分和GC执行时间,觉得是否进行优化; 

1.  **分析结果,判断是否需要优化** 

如果各项参数设置合理,系统没有超时日志出现,GC频率不高,GC耗时不高,那么没有必要进行GC优化;如果GC时间超过1-3秒,或者频繁GC,则必须优化; 

注:**如果满足下面的指标,则一般不需要进行****GC**: 

Minor GC执行时间不到50ms; 

Minor GC执行不频繁,约10秒一次; 

 **Full GC****执行时间不到1s;** 

Full GC执行频率不算频繁,不低于10分钟1次; 

1.  **调整GC类型和内存分配** 

如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优先调整这些参数,并且先找1台或几台机器进行beta,然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择; 

1.  **不断的分析和调整** 

通过不断的试验和试错,分析并找到最合适的参数 

1.  **全面应用参数** 

如果找到了最合适的参数,则将这些参数应用到所有服务器,并进行后续跟踪。 

1.  ## 调优实例

上面的内容都是纸上谈兵,下面我们以一些真实例子来进行说明。 

1.  ### 实例1

笔者昨日发现部分开发测试机器出现异常: 

java.lang.OutOfMemoryError: GC overhead limit exceeded 

这个异常代表:GC为了释放很小的空间却耗费了太多的时间,其原因一般有两个 

1.  堆太小 
2.  有死循环或大对象 

笔者首先排除了第2个原因,因为这个应用同时是在线上运行的,如果有问题,早就挂了。所以怀疑是这台机器中堆设置太小; 

使用**ps -ef |grep "java"**  查看,发现: 

![image](https://upload-images.jianshu.io/upload_images/19559641-08743e64d64a4d25.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

该应用的堆区设置只有768m,而机器内存有2g,机器上只跑这一个java应用,没有其他需要占用内存的地方。另外,这个应用比较大,需要占用的内存也比较多; 

笔者通过上面的情况判断,只需要改变堆中各区域的大小设置即可,于是改成下面的情况: 

 ![image](https://upload-images.jianshu.io/upload_images/19559641-3fdb506dee30accd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 

跟踪运行情况发现,相关异常没有再出现; 

1.  ### 实例2](http://www.360doc.com/content/13/0305/10/15643_269388816.shtml) 

[](http://www.360doc.com/content/13/0305/10/15643_269388816.shtml)[http://www.360doc.com/content/13/0305/10/15643_269388816.shtml](http://www.360doc.com/content/13/0305/10/15643_269388816.shtml)  

一个服务系统,**经常出现卡顿,分析原因,发现****Full GC****时间太长**: 

jstat -gcutil: 

S0 S1 E O P YGC YGCT FGC FGCT GCT 

12.16 0.00 5.18 63.78 20.32 54 2.047 5 6.946 8.993 

分析上面的数据,发现Young GC执行了54次,耗时2.047秒,每次Young GC耗时37ms,在正常范围,**而****Full GC执行了5次,耗时6.946秒,每次平均1.389s,数据显示出来的问题是:Full GC****耗时较长**,分析该系统的是指发现,NewRatio=9,也就是说,新生代和老生代大小之比为1:9,这就是问题的原因: 

1.  新生代太小,导致对象提前进入老年代,触发老年代发生Full GC; 
2.  老年代较大,进行Full GC时耗时较大; 

优化的方法是调整NewRatio的值,调整到4,发现Full GC没有再发生,只有Young GC在执行。这就是把对象控制在新生代就清理掉,没有进入老年代(这种做法对一些应用是很有用的,但并不是对所有应用都要这么做) 

1.  ### 实例3

一应用在性能测试过程中,发现内存占用率很高,Full GC频繁,使用sudo -u admin -H jmap -dump:format=b,file=文件名.hprof pid 来dump内存,生成dump文件,并使用Eclipse下的mat差距进行分析,发现: 

 ![image](https://upload-images.jianshu.io/upload_images/19559641-36f4aa036b856b8c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 

从图中可以看出,这个线程存在问题,队列**LinkedBlockingQueue**所引用的大量对象并未释放,导致整个线程占用内存高达378m,此时通知开发人员进行代码优化,将相关对象释放掉即可。 

1.  ## 调优总结

    1.  ### 年轻代大小选择

*   **响应时间优先的应用**:**尽可能设大,直到接近系统的最低响应时间限制**(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。 
*   **吞吐量优先的应用**:尽可能的设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8CPU以上的应用。 

1.  ### 年老代大小选择

*   **响应时间优先的应用**:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑**并发会话率**和**会话持续时间**等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得: 

    *   并发垃圾收集信息 
    *   持久代并发收集次数 
    *   传统GC信息 
    *   花在年轻代和年老代回收上的时间比例 

减少年轻代和年老代花费的时间,一般会提高应用的效率 

*   **吞吐量优先的应用**:一般吞吐量优先的应用都有一个很大的年轻代和一个较小的年老代。原因是,这样可以尽可能回收掉大部分短期对象,减少中期的对象,而年老代尽存放长期存活对象。 

1.  ### 较小堆引起的碎片问题

因为年老代的并发收集器使用标记、清除算法,所以不会对堆进行压缩。当收集器回收时,他会把相邻的空间进行合并,这样可以分配给较大的对象。但是,当堆空间较小时,运行一段时间以后,就会出现"碎片",如果并发收集器找不到足够的空间,那么并发收集器将会停止,然后使用传统的标记、清除方式进行回收。如果出现"碎片",可能需要进行如下配置: 

*   **-XX:+UseCMSCompactAtFullCollection**:使用并发收集器时,开启对年老代的压缩。 
*   **-XX:CMSFullGCsBeforeCompaction=0**:上面配置开启的情况下,这里设置多少次Full GC后,对年老代进行压缩。 

**参考资料:** 
http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,125评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,293评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,054评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,077评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,096评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,062评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,988评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,817评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,266评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,486评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,646评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,375评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,974评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,621评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,642评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,538评论 2 352

推荐阅读更多精彩内容

  • 这篇文章是我之前翻阅了不少的书籍以及从网络上收集的一些资料的整理,因此不免有一些不准确的地方,同时不同JDK版本的...
    高广超阅读 15,595评论 3 83
  • Java动态追踪技术探究 在Java虚拟机中,字符串常量到底存放在哪 一次生产 CPU 100% 排查优化实践 聊...
    passiontim阅读 4,071评论 0 38
  • Java动态追踪技术探究 在Java虚拟机中,字符串常量到底存放在哪 一次生产 CPU 100% 排查优化实践 聊...
    星海辰光大人阅读 744评论 0 2
  • 查看端口号连接数 查看java进程id 查看进程下有多少线程 获取真正在running的线程数量 tomcat组件...
    有章阅读 2,296评论 0 1
  • 一、JDK JDK是 Java语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个...
    任总阅读 708评论 0 0