a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 235|回复: 3

[专业语言] JAVA认证考试专业语言基础知识28

[复制链接]
发表于 2012-8-4 12:44:44 | 显示全部楼层 |阅读模式
首先我们先看看Bruce Eckel是怎么说的:' Z, }) N' R' i5 S: J5 B1 I
   
. t% W! Z) ?- E8 S( B* G    In the JVM an increment is not atomic and involves both a read and a write. (via the latest Java Performance Tuning Newsletter)2 b) X% g; C6 m1 M  C
    1 u  o5 `* j8 ]5 t3 F
    意思很简单,就是说在jvm中自增不是原子性操作,它包含一个读操作和一个写操作。3 P' p0 L5 x" m+ g6 v
   
! p% V, Z% J/ M    2、以上可能还不能让你信服,要想让人心服口服,就必须用代码说话。正如FaceBook的文化一样:代码赢得争论。那我们就看一段代码:  m4 ]/ W3 c0 P9 s- A
    - g# e( Y) u) f& y! f2 k$ d
    以下的代码是用100个线程同时执行自增操作,每个线程自增100次,如果自增操作是原子性操作的话,那么执行完amount的值为10,000.运行代码之后,你会发现amount的值小于10,000,这就说明自增操作不是原子性的! V- w- ?" \; _% K  p+ U4 y2 B
    8 M' m  l# k+ E& j' T6 u) T, W0 i- J
    1./**
: _! w; M9 ^% @: m    7 p9 c$ Z( \, n; ^
    2. *
4 [1 k) Z' \. ?7 O  i5 `8 ^   
+ U+ }( h% X4 c0 u    3. * @author renrun.wu; ]+ a( I+ B0 x/ V# j/ v
    3 ], J, b. C9 o) X
    4. */- Y6 u+ A) f: |9 g/ k( c' p) H  k. U
    9 N. s6 r% @/ ]0 M. @, _8 V4 J
    5.public class MultiThread implements Runnable {8 Y/ h: Z7 ]7 g: z5 ?
   
3 ^' ]( ~" I& n& ^    6.    private int count;: b7 u6 G- {( K$ L: c1 o# V5 R
    8 H! ]7 q% ]) S/ t1 A
    7.    private int amount = 1;
, y8 [8 `) ]0 _  E& p2 v6 Q    ( ?$ z! B  w$ W  g! o2 x
    8.& S1 \& t  [* z3 f
    2 |9 L! ]+ f# Y# V4 q: J# \- d
    9.    public MultiThread() {
  u7 ?, q; l+ T    ( R( j1 ?5 v1 V( [+ U/ w0 w7 M- D
    10.         count = 100;0 ]' a6 s4 r# W% z8 I, f
    * ^2 [* u" G* ]4 D; T8 o- B, H
    11.    }
$ d2 x3 L( H% Q8 D. j- q    + V3 q! G( ~2 O! l* u) D5 a" C
    12.
4 ^0 B2 E; V) w  `( K0 F3 b3 H! U9 ?   
7 D8 F" q/ h4 F# t( S    13.    public MultiThread(int count) {0 Z  t7 t6 J# H  F6 C
   
1 o% P2 Z: M& |  p    14.        this.count = count;2 U% ^! ^: M& ?, \) z+ k
   
& S, g6 N- T6 `    15.    }; f; ^3 A  z9 A% B
    ! B; X3 B6 Y6 g$ v/ W1 j9 x1 G1 \
    16.
回复

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:45 | 显示全部楼层

JAVA认证考试专业语言基础知识28

17.    @Override
$ G' c' H& a6 w      j4 i/ ^0 R; f0 w0 Z
    18.    public void run() {/ |" A& f1 O7 X/ `$ n% h, t! f
    2 a5 P; D8 T% F9 Z; `; T. ]
    19.        for (int i = 0; i < count; i++) {8 s5 T9 X, e( ~5 N7 m7 v" w
   
3 @; U5 b9 `' P1 M3 R& C    20.            amount++;( i, j- w: p( I! b7 t
    4 e# n9 \# B, C% U7 k
    21.        }
+ l2 ~$ n. t  b% `6 h# G& e   
3 u+ G' d0 I: H. r0 E8 J& f    22.    }3 D# V7 L/ {2 c2 E. i
    / Q1 u2 ~1 j, z0 ]9 l4 W
    23.
) P4 k! H0 _# I- e    . i4 K* d; \9 }8 Y3 R! h
    24.    public static void main(String[] args) {
: ^' W$ V3 T( j& s$ h4 R9 F8 Z      u* L: O$ E2 `4 n) \9 V
    25.        ExecutorService executorService = Executors.newCachedThreadPool();
+ g7 {7 \9 N4 Z- X" E7 N  \4 \   
) m0 a: o1 Z& ~( k5 F    26.        MultiThread multiThread =new MultiThread();
' D& A  A9 c4 ?   
/ f; R2 ^! u8 B9 W1 y    27.        for (int i = 0; i < 100; i++) {
. `0 }# H! N. O4 `" o0 Q   
  ?  N% T" W2 R6 |+ r9 d    28.            executorService.execute(multiThread);1 ]( u' x$ t8 w  M5 k0 Q
    , x  z7 W  a" t: e
    29.        }. g$ D6 i* a7 O, @( \, m2 \/ n
    ( }0 ]$ h9 T% k- W9 y  L5 l  W
    30.        executorService.shutdown();
! f9 b4 f/ O) a   
. a: U' K$ `5 ~5 R: e    31.0 z$ I% \( ~; g
    6 |8 o3 a7 `  k. d5 p
    32.        try {+ Z3 s0 x5 X+ c/ H' U& ]8 J3 B  P- X
   
, `; P! M0 h7 I    33.            Thread.sleep(60000);
) \% j" z) o3 E" T4 n4 q( Q    - k3 u3 p* {9 q' O0 {
    34.        } catch (InterruptedException e) {! N8 E6 v9 X+ q" m
   
. L6 d/ z! R" ~    35.            e.printStackTrace();
) t3 s' B1 M% S6 E9 _      \' i) r  m3 }. m
    36.        }
0 B+ o6 d+ Q" Z# \    5 Z6 }/ M" B9 ~, C1 ^) K0 j& V) S! l
    37.        System.out.println(multiThread.amount);
7 {) T& n4 G' W5 S& @. {    % b  [, m0 j7 T/ Z7 d% m1 j
    38.    }
. w; G/ d7 j! y3 i  n    2 x3 z1 a0 x& t6 l
    39.}
: ]  I( I5 ?7 W3 \( s   
) p: i" f& j0 }    3、如果以上还不能让你信服的话,也没关系。我们就把自增操作反编译出来,看看java字节码是怎么操作的
/ p  ~' _' X2 V" E3 ]1 ~% z   
3 h( t; x: T# l$ D- _: C& |    以下是一个简单的自增操作代码& g" J$ r8 _5 C; D9 @
   
1 F" _) N0 v! U$ }+ R    1.public class Increment {; n3 ^$ g+ d4 Q6 J7 Z
   
( z" D8 Y! C: n- ?8 q7 E; x    2.    private int id = 0;
) b! c' q8 F4 H! s' P( L   
% X. J6 W; K+ e- `: b' X    3.4.    public void getNext(){
; y1 i" t* M. n7 M# D( ^3 H   
# y2 W3 K( U$ _/ G( X- ]    5.        id++;
) \$ N# O) [0 D$ H; B   
4 b5 n5 d2 \/ C6 y    6.    }
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:46 | 显示全部楼层

JAVA认证考试专业语言基础知识28

7.}1 b6 K; s5 T8 V. j% D1 ?+ G% `
    7 R2 {* M6 T" J9 {1 B. X( k
    我们看看反编译之后的Java字节码,主要关注getNext()方法内部的Java字节码。
# H6 @# ~) Y) C4 ]; ~/ D5 Z5 E0 i" l    ! Y1 i0 G; W0 ~
    1.public class Increment extends java.lang.Object{
, U+ C0 U8 p1 y% ^# ^+ U    " p* G. E+ D" |1 W
    2.    public Increment();  s  H8 h) q6 V% X) g" o+ D
    6 Z% t0 e2 X" |$ |) S& H
    3.      Code:7 L5 @2 K# b0 p8 t8 z5 J
   
- ?, F; c' s" U6 I9 D    4.:   aload_0- r$ T; x- S/ d- A& ^0 e
   
0 X/ U( w% G5 }2 E9 M8 [' w2 {* I0 H    5.:   invokespecial   #1; //Method java/lang/Object."":()V' h  }5 n, D3 j$ K$ I5 G
   
+ R. A6 g, Z) }, N5 f5 v    6.:   aload_04 Z; p  ]5 t& [5 g
   
$ ?4 l9 O, n, y& N5 H) _* j# W9 |5 ?    7.:   iconst_0
3 G% [4 V, H+ N: s" S+ M3 j    ( W5 u& o# t' I2 F3 R4 g
    8.:   putfield        #2; //Field id:I
) {' J6 {' f2 H  h) n5 M    9 Z$ ?9 U: d# W: ~1 ~, K
    9.:   return( B/ G" Q6 x2 T, N7 C" q3 v2 i7 M2 o
    2 c5 c6 T# E. |
    10." a. j: S$ {0 h1 l+ o) A
    9 x7 m* B2 f1 e$ o. ]( x4 z: w
    11.    public void getNext();
" l% _  F2 _+ q    3 T; S3 c) x7 c+ ^
    12.      Code:" Q  i4 |. _8 w% A- M, d+ \# t6 A
    % ]! H' |$ B1 F) C$ x
    13.:   aload_0   //加载局部变量表index为0的变量,在这里是this
% O% Z8 C" d3 |$ q& E/ M    ( L* q1 T$ }8 G8 z/ t+ p' C
    14.:   dup                 //将当前栈顶的对象引用复制一份
* |/ o4 h/ h$ _- ~, }- l. M% [9 G   
  {) n% e& m" O" s2 }4 W+ s2 T    15.:   getfield        #2; //Field id:I,获取id的值,并将其值压入栈顶
; t# p4 g$ j2 [$ D" |   
; P5 }0 [  ]$ b    16.:   iconst_1            //将int型的值1压入栈顶
$ D6 e% L% p" J    / c' u' d3 O. D* E6 Q# X
    17.:   iadd                //将栈顶两个int类型的元素相加,并将其值压入栈顶9 T8 h! D/ B5 f! f1 c9 a& Y8 a
   
; w& V; U$ M! V    18.:   putfield        #2; //Field id:I,将栈顶的值赋值给id
% O4 D. W; Y+ H$ \8 G% ?& l    & u# T4 T* }( X+ o/ U: e
    19.:  return6 t( I+ Z/ J1 L* e$ {2 s
    # K! v) ?1 b1 C4 K* J
    20.
  E+ I4 v% w4 b$ H% g8 \   
& P+ G6 B4 Q0 B* c    21.    }
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-8-4 12:44:47 | 显示全部楼层

JAVA认证考试专业语言基础知识28

很明显,我们能够看到在getNext()方法内部,对于类变量id有一个先取值后加一再赋值的过程。因此,我们可以很肯定的说Java中的自增操作不是原子性的。
5 T- y# b1 {5 m% h6 l) ]6 ^      D$ O! o7 \! S+ A1 j
    4、也许你会问,那局部变量的自增操作是否是原子性的。好,我们在看看一下代码:/ W/ R3 ]- i3 l; w- _- _6 |: W
   
- a  t2 [& x" Z    1.public class Increment {
) Y* m% M1 Q* l$ R2 V2 t  d    3 `- X% ?9 B) ^
    2.    public void getNext(){
# D7 ?1 _5 L3 b& K% f5 t    ( a' K4 H2 g  p% w6 c3 e
    3.    int id = 0;% w3 {: v' S/ }6 I7 r6 K+ }1 R
   
- x; q* {2 H) }, a; h    4.        id++;8 ]7 W1 [5 I4 Y2 W4 C) P9 o/ `% y
    ! I/ B, s+ ~- G. c/ C1 ?* j7 t! N. p
    5.    }
) Q; O/ Q( m& @+ X    - P3 g/ ^* m/ l
    6.}8 o1 g; L# R' W3 z
    ; x, x* b3 o+ ]. g! B
    我们再看看反编译之后的Java字节码,主要还是关注getNext()方法内部的Java字节码。1 ^3 @4 Q+ W" x
    0 W4 e! h; y9 q$ U4 K1 v
    1.public class Increment extends java.lang.Object{* \8 _9 m. Y$ {2 i$ L& E
   
" Z$ _$ p1 g  j/ D# B7 G( Q6 Z! b0 }    2.public Increment();
% _2 c% N6 a2 U- `   
6 {6 ^* |0 \$ P. R/ M9 v4 m    3.  Code:& T$ A5 N( [  l5 ^/ {5 |: d0 g
   
& b4 C5 G- _4 }1 V    4.:   aload_06 _) \+ m/ c. `, O! e4 i( D9 T2 Z
   
- X. u; r9 G7 i* j0 M$ l, D, Y7 k    5.:   invokespecial   #1; //Method java/lang/Object."":()V
" Z4 W1 E: m: C( @6 o# D$ Y( c- m7 H   
6 l5 Y' [! _/ }% B7 p- U    6.:   return
5 E3 s+ O8 [' x    " X% M: B& c7 }2 `: z% o* |5 p
    7.3 W4 E6 F/ i: F! I' z! ^& n
    * e: H" Z8 ~4 L* \* Y
    8.public void getNext();
5 t3 S, T0 E" I& q9 T1 Q    1 ^# |! g  q) [& R9 D- S  `# v
    9.  Code:# y' @! ]/ I5 y- }  z
    * \! o8 x1 u* L5 Z/ i
    10.:   iconst_0
' V3 `/ l! `3 b$ I! L    . y# T5 M4 ]) L- @$ S
    11.:   istore_1+ y( u: o7 L* I% a
   
+ e" n: V$ @; f5 J- a1 b$ ^    12.:   iinc    1, 10 E$ A& K% U9 A8 J, L2 _
   
/ u" c( Z1 e% D# T, o    13.:   return
* e" b, ~$ G6 S' ^   
# d  u. G1 o, w5 _' _+ I- t2 U    14.. n3 A8 e7 M7 ^
    & i8 S& s' N* |0 A
    15.}& n% o  ~6 O2 Z" ]
    ; x$ Z- l# [# u6 V1 N8 o
    与全局变量的自增操作相比,很明显局部变量的自增操作少了getfield与putfield操作。而且对于局部变量来说,它无论如何都不会涉及到多线程的操作,因此局部变量的自增操作是否是原子操作也就显得不那么重要了。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-4-28 17:00 , Processed in 0.419148 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表