-
Notifications
You must be signed in to change notification settings - Fork 0
/
feed.xml
5118 lines (4923 loc) · 274 KB
/
feed.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?><rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>wngn123-GitBlog</title>
<description>GitBlog是一个简单易用的Markdown博客系统</description>
<link>/</link>
<atom:link href="//feed.xml" rel="self" type="application/rss+xml" />
<pubDate>2016-09-13 15:09:33</pubDate>
<lastBuildDate>2016-09-13 15:09:33</lastBuildDate>
<generator>Gitblog v1.0</generator>
<item>
<title>JVM工具 jmap</title>
<description>
<!--
author: wngn123
head: head.png
date: 2016-09-13
title: JVM工具 jmap
tags: java jvm jmap
category: Java
status: publish
summary: JVM工具 jmap
-->
<h2>简介</h2>
<p>打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其数量)。</p>
<p>可以输出所有内存中对象的工具,甚至可以将JVM中的heap,以二进制输出成文本。使用方法<code>jmap -histo pid</code>。如果连用<code>SHELL jmap -histo pid&gt;a.log</code>可以将其保存到文本中去,在一段时间后,使用文本对比工具,可以对比出GC回收了哪些对象。<code>jmap -dump:format=b,file=outfile 3024</code>可以将3024进程的内存heap输出出来到outfile文件里,再配合MAT(内存分析工具(Memory Analysis Tool),使用参见:<a href="http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx"><a href="http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx">http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx</a></a> 或与jhat (Java Heap Analysis Tool)一起使用,能够以图像的形式直观的展示当前内存是否有问题。</p>
<p>64位机上使用需要使用如下方式:</p>
<pre><code>jmap -J-d64 -heap pid</code></pre>
<h2>语法</h2>
<pre><code>Usage:
jmap [option] &lt;pid&gt;
(to connect to running process)
jmap [option] &lt;executable &lt;core&gt;
(to connect to a core file)
jmap [option] [server_id@]&lt;remote server IP or hostname&gt;
(to connect to remote debug server)
where &lt;option&gt; is one of:
&lt;none&gt; to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live"
suboption is specified, only count live objects
-clstats to print class loader statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:&lt;dump-options&gt; to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=&lt;file&gt; dump heap to &lt;file&gt;
Example: jmap -dump:live,format=b,file=heap.bin &lt;pid&gt;
-F force. Use with -dump:&lt;dump-options&gt; &lt;pid&gt; or -histo
to force a heap dump or histogram when &lt;pid&gt; does not
respond. The "live" suboption is not supported
in this mode.
-h | -help to print this help message
-J&lt;flag&gt; to pass &lt;flag&gt; directly to the runtime system
</code></pre>
<h2>jmap –heap pid</h2>
<pre><code>[work@wanggang oom] jmap -heap 5773
Attaching to process ID 5773, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.91-b14
using parallel threads in the new generation. ##新生代采用的是并行线程处理方式
using thread-local object allocation.
Concurrent Mark-Sweep GC ##同步并行垃圾回收
Heap Configuration: ##堆配置情况
MinHeapFreeRatio = 40 ##最小堆使用比例
MaxHeapFreeRatio = 70 ##最大堆可用比例
MaxHeapSize = 1073741824 (1024.0MB) ##最大堆空间大小
NewSize = 348913664 (332.75MB) ##新生代分配大小
MaxNewSize = 348913664 (332.75MB) ##最大可新生代分配大小
OldSize = 187957248 (179.25MB) ##老生代大小
NewRatio = 2 ##新生代比例
SurvivorRatio = 8 ##新生代与suvivor的比例
MetaspaceSize = 21807104 (20.796875MB) ##perm区大小
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB ##最大可分配perm区大小
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:##堆使用情况
New Generation (Eden + 1 Survivor Space):##新生代(伊甸区 + survior空间)
capacity = 314048512 (299.5MB) ##伊甸区容量
used = 50253216 (47.925201416015625MB) ##已经使用大小
free = 263795296 (251.57479858398438MB) ##剩余容量
16.001736699838272% used ##使用比例
Eden Space:##伊甸区
capacity = 279183360 (266.25MB) ##伊甸区容量
used = 50253216 (47.925201416015625MB) ##伊甸区使用
free = 228930144 (218.32479858398438MB) #伊甸区当前剩余容量
18.000075649207748% used ##伊甸区使用情况
From Space: ##survior1区
capacity = 34865152 (33.25MB) ##survior1区容量
used = 0 (0.0MB) ##surviror1区已使用情况
free = 34865152 (33.25MB) ##surviror1区剩余容量
0.0% used ##survior1区使用比例
To Space: ##survior2 区
capacity = 34865152 (33.25MB) ##survior2区容量
used = 0 (0.0MB) ##survior2区已使用情况
free = 34865152 (33.25MB)##survior2区剩余容量
0.0% used ## survior2区使用比例
concurrent mark-sweep generation: ##老生代使用情况
capacity = 187957248 (179.25MB) ##老生代容量
used = 0 (0.0MB)##老生代已使用容量
free = 187957248 (179.25MB)##老生代剩余容量
0.0% used ##老生代使用比例
3589 interned Strings occupying 288776 bytes.
</code></pre> </description>
<pubDate>2016-09-13 15:52:04</pubDate>
<link>//blog/java-jvm-jmap.html</link>
<guid isPermaLink="true">//blog/java-jvm-jmap.html</guid>
<category>Java</category>
</item>
<item>
<title>JVM工具 jstack</title>
<description>
<!--
author: wngn123
head: head.png
date: 2016-09-13
title: JVM工具 jstack
tags: java jvm jstack
category: Java
status: publish
summary: JVM工具 jstack 主要用来查看某个Java进程内的线程堆栈信息
-->
<h2>简介</h2>
<p>jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项<code>-J-d64</code>,Windows的jstack使用方式只支持以下的这种方式<code>jstack [-l] pid</code></p>
<p>如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的</p>
<h2>语法</h2>
<pre><code>Usage:
jstack [-l] &lt;pid&gt;
(to connect to running process)
jstack -F [-m] [-l] &lt;pid&gt;
(to connect to a hung process)
jstack [-m] [-l] &lt;executable&gt; &lt;core&gt;
(to connect to a core file)
jstack [-m] [-l] [server_id@]&lt;remote server IP or hostname&gt;
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack &lt;pid&gt; does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message</code></pre>
<p><code>core</code> 将被打印信息的core dump文件</p>
<p><code>remote-hostname-or-IP</code> 远程debug服务的主机名或ip</p>
<p><code>server-id</code> 唯一id,假如一台主机上多个远程debug服务 </p>
<p><code>-F</code> 当<code>jstack [-l] pid</code>没有相应的时候强制打印栈信息</p>
<p><code>-l</code>长列表. 打印关于锁的附加信息,例如属于java.util.concurrent的ownable synchronizers列表.</p>
<p><code>-m</code>打印java和native c/c++框架的所有栈信息.</p>
<p><code>-h | -help</code>打印帮助信息</p>
<p><code>pid</code> 需要被打印配置信息的java进程id,可以用jps查询.</p>
<h2>使用</h2>
<p>jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps、top、printf、jstack、grep</p>
<p>第一步先找出Java进程ID,我部署在服务器上的Java应用名称为mrf-center:
<code>ps -ef | grep mrf-center | grep -v grep</code></p>
<p>第二步找出该进程内最耗费CPU的线程,可以使用<code>ps -Lfp pid</code>或者<code>ps -mp pid -o THREAD, tid, time</code>或者<code>top -Hp pid</code>,我这里用第三个, TIME列就是各个Java线程耗费的CPU时间</p>
<p><code>printf "%x\n" 21742</code>得到21742的十六进制值为54ee</p>
<p>jstack用来输出进程21711的堆栈信息,然后根据线程ID的十六进制值grep</p>
<p><code>stack 21711 | grep 54ee</code></p>
<h4>实例</h4>
<p><code>jstack -F 8339</code></p>
<pre><code>Attaching to process ID 8339, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.91-b14
Deadlock Detection:
No deadlocks found.
Thread 8357: (state = BLOCKED)
- java.lang.Thread.sleep(long) @bci=0 (Compiled frame; information may be imprecise)
- com.zzia.wngn.oom.task.MemTask.run() @bci=44, line=19 (Compiled frame)
- java.util.concurrent.ThreadPoolExecutor.runWorker(java.util.concurrent.ThreadPoolExecutor$Worker) @bci=95, line=1142 (Interpreted frame)
- java.util.concurrent.ThreadPoolExecutor$Worker.run() @bci=5, line=617 (Interpreted frame)
- java.lang.Thread.run() @bci=11, line=745 (Interpreted frame)
Thread 8350: (state = BLOCKED)
Thread 8349: (state = BLOCKED)
Thread 8348: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove(long) @bci=59, line=143 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove() @bci=2, line=164 (Compiled frame)
- java.lang.ref.Finalizer$FinalizerThread.run() @bci=36, line=209 (Interpreted frame)
Thread 8347: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait() @bci=2, line=502 (Compiled frame)
- java.lang.ref.Reference.tryHandlePending(boolean) @bci=54, line=191 (Compiled frame)
- java.lang.ref.Reference$ReferenceHandler.run() @bci=1, line=153 (Interpreted frame)
Thread 8340: (state = BLOCKED)
- java.lang.Thread.sleep(long) @bci=0 (Compiled frame; information may be imprecise)
- com.zzia.wngn.oom.OOMServer.main(java.lang.String[]) @bci=134, line=56 (Interpreted frame)
</code></pre> </description>
<pubDate>2016-09-13 15:49:37</pubDate>
<link>//blog/java-jvm-jstack.html</link>
<guid isPermaLink="true">//blog/java-jvm-jstack.html</guid>
<category>Java</category>
</item>
<item>
<title>JVM工具 jstat</title>
<description>
<!--
author: wngn123
head: head.png
date: 2016-09-13
title: JVM工具 jstat
tags: java jvm jstat
category: Java
status: publish
summary: JVM工具 jstat JVM统计监测工具
-->
<h2>简介</h2>
<p>Jstat用于监控基于HotSpot的JVM,对其堆的使用情况进行实时的命令行的统计,使用jstat我们可以对指定的JVM做如下监控:</p>
<ul>
<li>类的加载及卸载情况</li>
<li>查看新生代、老生代及持久代的容量及使用情况</li>
<li>查看新生代、老生代及持久代的垃圾收集情况,包括垃圾回收的次数及垃圾回收所占用的时间</li>
<li>查看新生代中Eden区及Survior区中容量及分配情况等</li>
</ul>
<p>jstat工具特别强大,它有众多的可选项,通过提供多种不同的监控维度,使我们可以从不同的维度来了解到当前JVM堆的使用情况。详细查看堆内各个部分的使用量,使用的时候必须加上待统计的Java进程号,可选的不同维度参数以及可选的统计频率参数。</p>
<p>它主要是用来显示GC及PermGen相关的信息,如果对GC不怎么了解,先看这篇文章
<a href="http://blog.csdn.net/fenglibing/archive/2011/04/13/6321453.aspx"><a href="http://blog.csdn.net/fenglibing/archive/2011/04/13/6321453.aspx">http://blog.csdn.net/fenglibing/archive/2011/04/13/6321453.aspx</a></a></p>
<h2>语法</h2>
<pre><code>Usage: jstat -help|-options
jstat -&lt;option&gt; [-t] [-h&lt;lines&gt;] &lt;vmid&gt; [&lt;interval&gt; [&lt;count&gt;]]
Definitions:
&lt;option&gt; An option reported by the -options option
&lt;vmid&gt; Virtual Machine Identifier. A vmid takes the following form:
&lt;lvmid&gt;[@&lt;hostname&gt;[:&lt;port&gt;]]
Where &lt;lvmid&gt; is the local vm identifier for the target
Java virtual machine, typically a process id; &lt;hostname&gt; is
the name of the host running the target Java virtual machine;
and &lt;port&gt; is the port number for the rmiregistry on the
target host. See the jvmstat documentation for a more complete
description of the Virtual Machine Identifier.
&lt;lines&gt; Number of samples between header lines.
&lt;interval&gt; Sampling interval. The following forms are allowed:
&lt;n&gt;["ms"|"s"]
Where &lt;n&gt; is an integer and the suffix specifies the units as
milliseconds("ms") or seconds("s"). The default units are "ms".
&lt;count&gt; Number of samples to take before terminating.
-J&lt;flag&gt; Pass &lt;flag&gt; directly to the runtime system.
</code></pre>
<p><code>&lt;option&gt;</code> 选项,我们一般使用 -gcutil 查看gc情况</p>
<p><code>&lt;vmid&gt;</code> vmid 是Java虚拟机ID,在Linux/Unix系统上一般就是进程ID</p>
<p><code>&lt;lines&gt;</code> lines 行数</p>
<p><code>&lt;interval&gt;</code> interval是监控时间间隔,单位为微妙,不提供就意味着单次输出</p>
<p><code>&lt;count&gt;</code> count是最大输出次数,不提供且监控时间间隔有值的话, 就无限打印</p>
<p>参数interval和count代表查询间隔和次数,如果省略这两个参数,说明只查询一次。假设需要每250毫秒查询一次进程5828垃圾收集状况,一共查询5次,那命令行如下</p>
<p><code>jstat -gc 5828</code></p>
<p>选项option代表这用户希望查询的虚拟机信息,主要分为3类:类装载、垃圾收集和运行期编译状况,具体选项及作用如下:</p>
<ul>
<li><code>–class</code> 监视类装载、卸载数量、总空间及类装载所耗费的时间,统计classloader的行为</li>
<li><code>–gc</code> 监视Java堆状况,包括Eden区、2个Survivor区、老年代、永久代等的容量,统计gc行为</li>
<li><code>–gccapacity</code> 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大和最小空间</li>
<li><code>–gcutil</code> 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比</li>
<li><code>–gccause</code> 与-gcutil功能一样,但是会额外输出导致上一次GC产生的原因</li>
<li><code>–gcnew</code> 监视新生代GC的状况</li>
<li><code>–gcnewcapacity</code> 监视内容与-gcnew基本相同,输出主要关注使用到的最大和最小空间</li>
<li><code>–gcold</code> 监视老年代GC的状况</li>
<li><code>–gcoldcapacity</code> 监视内容与——gcold基本相同,输出主要关注使用到的最大和最小空间</li>
<li><code>–gcpermcapacity</code> 输出永久代使用到的最大和最小空间</li>
<li><code>–compiler</code> 输出JIT编译器编译过的方法、耗时等信息,统计hotspot just-in-time编译器的行为</li>
<li><code>–printcompilation</code> 输出已经被JIT编译的方法</li>
</ul>
<p>-h n 每n个样本,显示header一次
-t n 在第一列显示时间戳列,时间戳时从jvm启动开始计算</p>
<h2>输出GC信息 jstat -gc</h2>
<h4>jstat -gc pid interval count</h4>
<p>输出的是GC信息,采样时间间隔为250ms,采样数为4</p>
<p><code>jstat -gc 21711 250 4</code></p>
<pre><code>S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT
192.0 192.0 64.0 0.0 6144.0 1854.9 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649
192.0 192.0 64.0 0.0 6144.0 1972.2 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649
192.0 192.0 64.0 0.0 6144.0 1972.2 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649
192.0 192.0 64.0 0.0 6144.0 2109.7 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649</code></pre>
<pre><code>堆内存 = 年轻代 + 年老代 + 永久代
年轻代 = Eden区 + 两个Survivor区(From和To)
S0C、S1C、S0U、S1U:Survivor 0/1区容量(Capacity)和使用量(Used)
EC、EU:Eden区容量和使用量
OC、OU:年老代容量和使用量
PC、PU:永久代容量和使用量
YGC、YGT:年轻代GC次数和GC耗时
FGC、FGCT:Full GC次数和Full GC耗时
GCT:GC总耗时
</code></pre>
<h2>输出GC信息 jstat -gcutil</h2>
<h4>jstat -gcutil pid interval count</h4>
<p><code>jstat -gcutil 8339</code></p>
<pre><code> S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 44.09 0.00 17.27 19.75 0 0.000 0 0.000 0.000</code></pre>
<pre><code>S0 — Heap上的 Survivor space 0 区已使用空间的百分比
S1 — Heap上的 Survivor space 1 区已使用空间的百分比
E — Heap上的 Eden space 区已使用空间的百分比
O — Heap上的 Old space 区已使用空间的百分比
P — Perm space 区已使用空间的百分比
YGC — 从应用程序启动到采样时发生 Young GC 的次数
YGCT– 从应用程序启动到采样时 Young GC 所用的时间(单位秒)
FGC — 从应用程序启动到采样时发生 Full GC 的次数
FGCT– 从应用程序启动到采样时 Full GC 所用的时间(单位秒)
GCT — 从应用程序启动到采样时用于垃圾回收的总时间(单位秒)</code></pre>
<h2>输出class信息</h2>
<h4>jstat -class pid</h4>
<p>显示加载class的数量,及所占空间等信息。</p>
<pre><code>[work@wanggang oom] jstat -class 8339
Loaded Bytes Unloaded Bytes Time
1893 3556.3 0 0.0 3.36</code></pre>
<pre><code>Loaded 装载的类的数量
Bytes 装载类所占用的字节数
Unloaded 卸载类的数量
Bytes 卸载类的字节数
Time 装载和卸载类所花费的时间</code></pre>
<h2>显示VM实时编译的数量等信息 jstat -compiler</h2>
<h4>jstat -compiler pid</h4>
<pre><code>Compiled 编译任务执行数量
Failed 编译任务执行失败数量
Invalid 编译任务执行失效数量
Time 编译任务消耗时间
FailedType 最后一个编译失败任务的类型
FailedMethod 最后一个编译失败任务所在的类及方法</code></pre>
<h2>显示对象大小 jstat -gccapacity</h2>
<p>显示VM内存中三代(young,old,perm)对象的使用和占用大小 </p>
<h4>jstat -gccapacity pid</h4>
<pre><code>NGCMN 年轻代(young)中初始化(最小)的大小(字节)
NGCMX 年轻代(young)的最大容量 (字节)
NGC 年轻代(young)中当前的容量 (字节)
S0C 年轻代中第一个survivor(幸存区)的容量 (字节)
S1C 年轻代中第二个survivor(幸存区)的容量 (字节)
EC 年轻代中Eden(伊甸园)的容量 (字节)
OGCMN old代中初始化(最小)的大小 (字节)
OGCMX old代的最大容量(字节)
OGC old代当前新生成的容量 (字节)
OC Old代的容量 (字节)
PGCMN perm代中初始化(最小)的大小 (字节)
PGCMX perm代的最大容量 (字节)
PGC perm代当前新生成的容量 (字节)
PC Perm(持久代)的容量 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数</code></pre>
<h2>年轻代对象的信息 jstat -gcnew</h2>
<h4>jstat -gcnew pid</h4>
<pre><code>S0C 年轻代中第一个survivor(幸存区)的容量 (字节)
S1C 年轻代中第二个survivor(幸存区)的容量 (字节)
S0U 年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U 年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
TT 持有次数限制
MTT 最大持有次数限制
EC 年轻代中Eden(伊甸园)的容量 (字节)
EU 年轻代中Eden(伊甸园)目前已使用空间 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)</code></pre>
<h2>年轻代对象的信息及其占用量 jstat -gcnewcapacity</h2>
<h4>jstat -gcnewcapacity pid</h4>
<pre><code>NGCMN 年轻代(young)中初始化(最小)的大小(字节)
NGCMX 年轻代(young)的最大容量 (字节)
NGC 年轻代(young)中当前的容量 (字节)
S0CMX 年轻代中第一个survivor(幸存区)的最大容量 (字节)
S0C 年轻代中第一个survivor(幸存区)的容量 (字节)
S1CMX 年轻代中第二个survivor(幸存区)的最大容量 (字节)
S1C 年轻代中第二个survivor(幸存区)的容量 (字节)
ECMX 年轻代中Eden(伊甸园)的最大容量 (字节)
EC 年轻代中Eden(伊甸园)的容量 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数</code></pre>
<h2>old代对象的信息 jstat -gcold</h2>
<h4>jstat -gcold pid</h4>
<pre><code>PC Perm(持久代)的容量 (字节)
PU Perm(持久代)目前已使用空间 (字节)
OC Old代的容量 (字节)
OU Old代目前已使用空间 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)</code></pre>
<h2>old代对象的信息及其占用量 jstat -gcoldcapacity</h2>
<h4>jstat -gcoldcapacity pid</h4>
<pre><code>OGCMN old代中初始化(最小)的大小 (字节)
OGCMX old代的最大容量(字节)
OGC old代当前新生成的容量 (字节)
OC Old代的容量 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)</code></pre>
<h2>perm对象的信息及其占用量 jstat -gcpermcapacity</h2>
<h4>jstat -gcpermcapacity pid</h4>
<pre><code>PGCMN perm代中初始化(最小)的大小 (字节)
PGCMX perm代的最大容量 (字节)
PGC perm代当前新生成的容量 (字节)
PC Perm(持久代)的容量 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)</code></pre>
<h2>当前VM执行的信息 jstat -printcompilation</h2>
<h4>jstat -printcompilation pid</h4>
<pre><code>Compiled 编译任务的数目
Size 方法生成的字节码的大小
Type 编译类型
Method 类名和方法名用来标识编译的方法。类名使用/做为一个命名空间分隔符。方法名是给定类中的方法。上述格式是由-XX:+PrintComplation选项进行设置的</code></pre> </description>
<pubDate>2016-09-13 15:49:37</pubDate>
<link>//blog/java-jvm-jstat.html</link>
<guid isPermaLink="true">//blog/java-jvm-jstat.html</guid>
<category>Java</category>
</item>
<item>
<title>JVM工具 jps</title>
<description>
<!--
author: wngn123
head: head.png
date: 2016-09-13
title: JVM工具 jps
tags: java jvm jps
category: Java
status: publish
summary: JVM工具 jps 用来查看所有的jvm进程,包括进程ID,进程启动的路径等
-->
<h2>介绍</h2>
<p>用来查看所有的jvm进程,包括进程ID,进程启动的路径等。</p>
<h2>语法</h2>
<pre><code>jps -help
usage: jps [-help]
jps [-q] [-mlvV] [&lt;hostid&gt;]
Definitions:
&lt;hostid&gt;: &lt;hostname&gt;[:&lt;port&gt;]</code></pre>
<h2>jps</h2>
<p>默认显示pid和class名称</p>
<pre><code>[work@wanggang oom] jps
6005 Jps
5773 OOMServer</code></pre>
<h2>-q参数</h2>
<p>只显示pid,不显示class名称,jar文件名和传递给main 方法的参数</p>
<pre><code>[work@wanggang oom] jps -q
6028
5773</code></pre>
<h2>-m参数</h2>
<p>输出传递给main 方法的参数,在嵌入式jvm上可能是null</p>
<pre><code>[work@wanggang oom] jps -m
6043 Jps -m
5773 OOMServer</code></pre>
<h2>-l参数</h2>
<p>输出应用程序main class的完整package名 或者 应用程序的jar文件完整路径名</p>
<pre><code>[work@wanggang oom] jps -l
6149 sun.tools.jps.Jps
5773 com.zzia.wngn.oom.OOMServer</code></pre>
<h2>-v参数(小写v)</h2>
<p>输出传递给JVM的参数</p>
<pre><code>[work@wanggang oom] jps -v
6164 Jps -Dapplication.home=/opt/dev/jdk/jdk1.8.0_91 -Xms8m
5773 OOMServer -Xmx1024m -Xms512m -XX:+UseConcMarkSweepGC</code></pre>
<h2>-V参数(大写V)</h2>
<p>输出通过文件传递给JVM的参数(如.hotspotrc或通过-XX:Flags=<filename>指定的文件)</p>
<pre><code>[work@wanggang oom] jps -V
6187 Jps
5773 OOMServer</code></pre>
<h2>参数合并使用</h2>
<p>参数mlvV可以合并一起使用,但是q不能和其他参数一起使用</p>
<pre><code>[work@wanggang oom] jps -mlv
6202 sun.tools.jps.Jps -mlv -Dapplication.home=/opt/dev/jdk/jdk1.8.0_91 -Xms8m
5773 com.zzia.wngn.oom.OOMServer -Xmx1024m -Xms512m -XX:+UseConcMarkSweepGC</code></pre> </description>
<pubDate>2016-09-13 15:49:37</pubDate>
<link>//blog/java-jvm-jps.html</link>
<guid isPermaLink="true">//blog/java-jvm-jps.html</guid>
<category>Java</category>
</item>
<item>
<title>Java线程 ThreadPoolExecutor</title>
<description>
<!--
author: wngn123
head: head.png
date: 2016-09-13
title: Java线程 ThreadPoolExecutor
tags: java
category: Java
status: publish
summary: 阅读Java的源码,Java线程,ThreadPoolExecutor
-->
<h2>Executor接口</h2>
<p>执行已提交的 Runnable 任务的对象。此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。通常使用 Executor 而不是显式地创建线程。例如,可能会使用以下方法,而不是为一组任务中的每个任务调用 <code>new Thread(new(RunnableTask())).start()</code>: </p>
<pre><code> Executor executor = anExecutor;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
...</code></pre>
<p>不过,Executor 接口并没有严格地要求执行是异步的。在最简单的情况下,执行程序可以在调用者的线程中立即运行已提交的任务: </p>
<pre><code> class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}</code></pre>
<p>更常见的是,任务是在某个不是调用者线程的线程中执行的。以下执行程序将为每个任务生成一个新线程。 </p>
<pre><code> class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}</code></pre>
<p>许多 Executor 实现都对调度任务的方式和时间强加了某种限制。以下执行程序使任务提交与第二个执行程序保持连续,这说明了一个复合执行程序。 </p>
<pre><code> class SerialExecutor implements Executor {
final Queue&lt;Runnable&gt; tasks = new ArrayDeque&lt;Runnable&gt;();
final Executor executor;
Runnable active;
SerialExecutor(Executor executor) {
this.executor = executor;
}
public synchronized void execute(final Runnable r) {
tasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (active == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((active = tasks.poll()) != null) {
executor.execute(active);
}
}
}</code></pre>
<p>此包中提供的 Executor 实现实现了 ExecutorService,这是一个使用更广泛的接口。ThreadPoolExecutor 类提供一个可扩展的线程池实现。Executors 类为这些 Executor 提供了便捷的工厂方法。
内存一致性效果:线程中将 Runnable 对象提交到 Executor 之前的操作 happen-before 其执行开始(可能在另一个线程中)。 </p>
<pre><code>public interface Executor {
//在未来某个时间执行给定的命令
void execute(Runnable command);
}
</code></pre>
<h2>ExecutorService接口</h2>
<p>Executor 提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。 </p>
<p>可以关闭 ExecutorService,这将导致其拒绝新任务。提供两个方法来关闭 ExecutorService。<code>shutdown()</code> 方法在终止前允许执行以前提交的任务,而 <code>shutdownNow()</code> 方法阻止等待任务启动并试图停止当前正在执行的任务。在终止时,执行程序没有任务在执行,也没有任务在等待执行,并且无法提交新任务。应该关闭未使用的 ExecutorService 以允许回收其资源。 </p>
<p>通过创建并返回一个可用于取消执行和/或等待完成的 <code>Future</code>,方法 <code>submit</code> 扩展了基本方法<code>Executor.execute(java.lang.Runnable)</code>。方法 <code>invokeAny</code> 和 <code>invokeAll</code> 是批量执行的最常用形式,它们执行任务 collection,然后等待至少一个,或全部任务完成(可使用 <code>ExecutorCompletionService</code> 类来编写这些方法的自定义变体)。 </p>
<p>Executors 类提供了用于此包中所提供的执行程序服务的工厂方法。 </p>
<pre><code>shutdown()
shutdownNow()
isShutdown()
isTerminated()
awaitTermination(long, TimeUnit)
submit(Callable&lt;T&gt;)
submit(Runnable, T)
submit(Runnable)
invokeAll(Collection&lt;? extends Callable&lt;T&gt;&gt;)
invokeAll(Collection&lt;? extends Callable&lt;T&gt;&gt;, long, TimeUnit)
invokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt;)
invokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt;, long, TimeUnit)</code></pre>
<pre><code>public interface ExecutorService extends Executor {
//启动一次顺序关闭,执行以前提交的任务,但不接受新任务。如果已经关闭,则调用没有其他作用。
void shutdown();
/**
* 试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
* 无法保证能够停止正在处理的活动执行任务,但是会尽力尝试。
* 例如,通过 Thread.interrupt() 来取消典型的实现,所以任何任务无法响应中断都可能永远无法终止
*/
List&lt;Runnable&gt; shutdownNow();
//如果此执行程序已关闭,则返回 true
boolean isShutdown();
//如果关闭后所有任务都已完成,则返回 true。注意,除非首先调用 shutdown 或 shutdownNow,否则 isTerminated 永不为 true。
boolean isTerminated();
/**
* 请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。
* @param timeout 最长等待时间
* @param unit timeout参数的时间单位
* @return 如果此执行程序终止,则返回 true;如果终止前超时期满,则返回 false
*/
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
/**
* 提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
* 该 Future 的 get 方法在成功完成时将会返回该任务的结果。
* 如果想立即阻塞任务的等待,则可以使用 result = exec.submit(aCallable).get(); 形式的构造。
*/
&lt;T&gt; Future&lt;T&gt; submit(Callable&lt;T&gt; task);
/**
* 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
* 该 Future 的 get 方法在成功完成时将会返回给定的结果。
*/
&lt;T&gt; Future&lt;T&gt; submit(Runnable task, T result);
/**
* 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
* 该 Future 的 get 方法在成功完成时将会返回 null。
*/
Future&lt;?&gt; submit(Runnable task);
/**
* 执行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表。
* 返回列表的所有元素的 Future.isDone() 为 true。
* 注意,可以正常地或通过抛出异常来终止已完成 任务。如果正在进行此操作时修改了给定的 collection,则此方法的结果是不确定的。
*/
&lt;T&gt; List&lt;Future&lt;T&gt;&gt; invokeAll(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks) throws InterruptedException;
/**
* 执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。
* 返回列表的所有元素的 Future.isDone() 为 true。一旦返回后,即取消尚未完成的任务。
* 注意,可以正常地或通过抛出异常来终止已完成 任务。如果此操作正在进行时修改了给定的 collection,则此方法的结果是不确定的
*/
&lt;T&gt; List&lt;Future&lt;T&gt;&gt; invokeAll(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks, long timeout, TimeUnit unit) throws InterruptedException;
/**
* 执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。一旦正常或异常返回后,则取消尚未完成的任务。
* 如果此操作正在进行时修改了给定的 collection,则此方法的结果是不确定的。
*/
&lt;T&gt; T invokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks) throws InterruptedException, ExecutionException;
/**
* 执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果。一旦正常或异常返回后,则取消尚未完成的任务。
* 如果此操作正在进行时修改了给定的 collection,则此方法的结果是不确定的。
*/
&lt;T&gt; T invokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
</code></pre>
<h2>AbstractExecutorService抽象类</h2>
<p>提供 ExecutorService 执行方法的默认实现。此类使用 newTaskFor 返回的 RunnableFuture 实现 submit、invokeAny 和 invokeAll 方法,默认情况下,RunnableFuture 是此包中提供的 FutureTask 类。例如,submit(Runnable) 的实现创建了一个关联 RunnableFuture 类,该类将被执行并返回。子类可以重写 newTaskFor 方法,以返回 FutureTask 之外的 RunnableFuture 实现。</p>
<pre><code>doInvokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt;, boolean, long)
invokeAll(Collection&lt;? extends Callable&lt;T&gt;&gt;)
invokeAll(Collection&lt;? extends Callable&lt;T&gt;&gt;, long, TimeUnit)
invokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt;)
invokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt;, long, TimeUnit)
newTaskFor(Runnable, T)
newTaskFor(Callable&lt;T&gt;)
submit(Runnable)
submit(Runnable, T)
submit(Callable&lt;T&gt;)</code></pre>
<pre><code>package java.util.concurrent;
import java.util.*;
public abstract class AbstractExecutorService implements ExecutorService {
/**
* 为给定可运行任务和默认值返回一个 RunnableFuture。
* @param runnable 将被包装的可运行任务
* @param value 用于所返回的将来任务的默认值
* @return a RunnableFuture,在运行的时候,它将运行底层可运行任务,作为 Future 任务,它将生成给定值作为其结果,并为底层任务提供取消操作。
*/
protected &lt;T&gt; RunnableFuture&lt;T&gt; newTaskFor(Runnable runnable, T value) {
return new FutureTask&lt;T&gt;(runnable, value);
}
/**
* 为给定可调用任务返回一个 RunnableFuture。
* @param callable 将包装的可调用任务
*/
protected &lt;T&gt; RunnableFuture&lt;T&gt; newTaskFor(Callable&lt;T&gt; callable) {
return new FutureTask&lt;T&gt;(callable);
}
/**
* 提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
* 该 Future 的 get 方法在成功完成时将会返回给定的结果。
*/
public Future&lt;?&gt; submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture&lt;Void&gt; ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
/**
* 提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
* 该 Future 的 get 方法在成功完成时将会返回该任务的结果。
* 如果想立即阻塞任务的等待,则可以使用 result = exec.submit(aCallable).get(); 形式的构造。
*/
public &lt;T&gt; Future&lt;T&gt; submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture&lt;T&gt; ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public &lt;T&gt; Future&lt;T&gt; submit(Callable&lt;T&gt; task) {
if (task == null) throw new NullPointerException();
RunnableFuture&lt;T&gt; ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
private &lt;T&gt; T doInvokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null)
throw new NullPointerException();
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
List&lt;Future&lt;T&gt;&gt; futures= new ArrayList&lt;Future&lt;T&gt;&gt;(ntasks);
ExecutorCompletionService&lt;T&gt; ecs =
new ExecutorCompletionService&lt;T&gt;(this);
// For efficiency, especially in executors with limited
// parallelism, check to see if previously submitted tasks are
// done before submitting more of them. This interleaving
// plus the exception mechanics account for messiness of main
// loop.
try {
// Record exceptions so that if we fail to obtain any
// result, we can throw the last exception we got.
ExecutionException ee = null;
long lastTime = timed ? System.nanoTime() : 0;
Iterator&lt;? extends Callable&lt;T&gt;&gt; it = tasks.iterator();
// Start one task for sure; the rest incrementally
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
for (;;) {
Future&lt;T&gt; f = ecs.poll();
if (f == null) {
if (ntasks &gt; 0) {
--ntasks;
futures.add(ecs.submit(it.next()));
++active;
}
else if (active == 0)
break;
else if (timed) {
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
else
f = ecs.take();
}
if (f != null) {
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
for (Future&lt;T&gt; f : futures)
f.cancel(true);
}
}
public &lt;T&gt; T invokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks)
throws InterruptedException, ExecutionException {
try {
return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) {
assert false;
return null;
}
}
public &lt;T&gt; T invokeAny(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
public &lt;T&gt; List&lt;Future&lt;T&gt;&gt; invokeAll(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
List&lt;Future&lt;T&gt;&gt; futures = new ArrayList&lt;Future&lt;T&gt;&gt;(tasks.size());
boolean done = false;
try {
for (Callable&lt;T&gt; t : tasks) {
RunnableFuture&lt;T&gt; f = newTaskFor(t);
futures.add(f);
execute(f);
}
for (Future&lt;T&gt; f : futures) {
if (!f.isDone()) {
try {
f.get();
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (Future&lt;T&gt; f : futures)
f.cancel(true);
}
}
public &lt;T&gt; List&lt;Future&lt;T&gt;&gt; invokeAll(Collection&lt;? extends Callable&lt;T&gt;&gt; tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
if (tasks == null || unit == null)
throw new NullPointerException();
long nanos = unit.toNanos(timeout);
List&lt;Future&lt;T&gt;&gt; futures = new ArrayList&lt;Future&lt;T&gt;&gt;(tasks.size());
boolean done = false;
try {
for (Callable&lt;T&gt; t : tasks)
futures.add(newTaskFor(t));
long lastTime = System.nanoTime();
// Interleave time checks and calls to execute in case
// executor doesn't have any/much parallelism.
Iterator&lt;Future&lt;T&gt;&gt; it = futures.iterator();
while (it.hasNext()) {
execute((Runnable)(it.next()));
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
if (nanos &lt;= 0)
return futures;
}
for (Future&lt;T&gt; f : futures) {
if (!f.isDone()) {
if (nanos &lt;= 0)
return futures;
try {
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
}
done = true;
return futures;
} finally {
if (!done)
for (Future&lt;T&gt; f : futures)
f.cancel(true);
}
}
}
</code></pre>
<h2>AtomicInteger原子操作int</h2>
<p>可以用原子方式更新的 int 值。AtomicInteger 可用在应用程序中(如以原子方式增加的计数器),并且不能用于替换 Integer。但是,此类确实扩展了 Number,允许那些处理基于数字类的工具和实用工具进行统一访问。 </p>
<pre><code>public class AtomicInteger extends Number implements java.io.Serializable {
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
public AtomicInteger(int initialValue) {
value = initialValue;
}
public AtomicInteger() {
}
public final int get() {
return value;
}
public final void set(int newValue) {
value = newValue;
}
/**
* 最后设置为给定值
*/
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
/**
* 以原子方式设置为给定值,并返回旧值。
*/
public final int getAndSet(int newValue) {
for (;;) {
int current = get();
if (compareAndSet(current, newValue))
return current;
}
}
/**
* 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* 如果当前值 == 预期值,则以原子方式将该设置为给定的更新值。
*/
public final boolean weakCompareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* 以原子方式将当前值加 1。
*/
public final int getAndIncrement() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return current;
}
}
/**
* 以原子方式将当前值减 1。
*/
public final int getAndDecrement() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return current;
}
}
/**
* 以原子方式将给定值与当前值相加
*/
public final int getAndAdd(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return current;
}
}
/**
* 以原子方式将当前值加 1。
*/
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
/**
* 以原子方式将当前值减 1。
*/
public final int decrementAndGet() {
for (;;) {
int current = get();
int next = current - 1;
if (compareAndSet(current, next))
return next;
}
}
/**
* 以原子方式将给定值与当前值相加。
*/
public final int addAndGet(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return next;
}