- 浏览: 404231 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
holleyangyanges:
name327 写道LZ说句打击你的话, 首先不说Https的 ...
使用httpclient4登录百度 -
holleyangyanges:
,没有登陆成功啊!
使用httpclient4登录百度 -
shenjichao2009:
...
Spring AOP原理解析 -
wuke0210:
[color=red][/color]
CKEditor3.0在asp.net环境下上传文件的配置,集成CKFinder -
wuke0210:
CKEditor3.0在asp.net环境下上传文件的配置,集成CKFinder
通过使用一些辅助性工具来找到程序中的瓶颈,然后就可以对瓶颈部分的代码进行优化。一般有两种方案:即优化代码或更改设计方法。我们一般会选择后者,因为不去调用以下代码要比调用一些优化的代码更能提高程序的性能。而一个设计良好的程序能够精简代码,从而提高性能。' r. x- r! w+ ~8 N3 X) V+ D& d
/ q* j) @) q, _8 _& P4 A
下面将提供一些在JAVA程序的设计和编码中,为了能够提高JAVA程序的性能,而经常采用的一些方法和技巧。
- _: K- h5 `( H
. }/ \3 Y i2 k/ a 1.对象的生成和大小的调整。
2 c' G" ~9 i* u$ B1 I6 z9 H
4 X: h+ r+ M, J JAVA程序设计中一个普遍的问题就是没有好好的利用JAVA语言本身提供的函数,从而常常会生成大量的对象(或实例)。由于系统不仅要花时间生成对象,以后可能还需花时间对这些对象进行垃圾回收和处理。因此,生成过多的对象将会给程序的性能带来很大的影响。
; Y- r8 I( c; P4 }$ ^0 ? ! y3 n0 E# _: Z8 O) l
例1:关于String ,StringBuffer,+和append0 h% H3 I- |& k; `
7 J6 D0 n9 T5 m1 V* e JAVA语言提供了对于String类型变量的操作。但如果使用不当,会给程序的性能带来影响。如下面的语句:$ o. _8 M u4 g, S/ `: B: t
3 T% e/ m1 u5 V6 ^/ V: k+ W String name=new String("HuangWeiFeng");
5 z2 z$ C0 Q5 O( p System.out.println(name+"is my name");* y' z5 J4 y9 D' Q
# ~, z0 T- t6 f( L5 h9 M 看似已经很精简了,其实并非如此。为了生成二进制的代码,要进行如下的步骤和操作:
6 u1 Z# c$ M! [ _/ Z0 a2 `' A" g" W
(1) 生成新的字符串 new String(STR_1);
% Y! I( Q, U; G5 i (2) 复制该字符串;
. Y: p% p8 T" P* G6 M6 e Y/ _ (3) 加载字符串常量"HuangWeiFeng"(STR_2);
{9 ^, t- M1 [3 v2 W3 C/ `2 o6 l (4) 调用字符串的构架器(Constructor);" a6 k9 c+ s+ t6 ~: C. P) p
(5) 保存该字符串到数组中(从位置0开始);) Y$ D) N$ Y/ [% D, M- Y
(6) 从java.io.PrintStream类中得到静态的out变量;
" x# n. i( P: V, u; o+ b (7) 生成新的字符串缓冲变量new StringBuffer(STR_BUF_1);
. P( M9 s' w0 }* F7 l1 Y (8) 复制该字符串缓冲变量;4 X( V3 u% M' s7 p
(9) 调用字符串缓冲的构架器(Constructor);
) }4 ?$ N/ C% p" L! [7 V1 |0 L (10) 保存该字符串缓冲到数组中(从位置1开始);
* v# ]6 X0 z8 u/ x (11) 以STR_1为参数,调用字符串缓冲(StringBuffer)类中的append方法;" w9 U3 D$ u7 y
(12) 加载字符串常量"is my name"(STR_3);8 y+ E4 F4 s$ q- K
(13) 以STR_3为参数,调用字符串缓冲(StringBuffer)类中的append方法;) L) f+ Y1 }7 {( r1 R( }, A
(14) 对于STR_BUF_1执行toString命令;
; D; K" G/ X! r9 v/ b (15) 调用out变量中的println方法,输出结果。4 W: x' b' l8 O; p9 n( G* R
* `9 c1 ]0 O8 g' }1 k7 J" S7 G 由此可以看 出,这两行简单的代码,就生成了STR_1,STR_2,STR_3,STR_4和STR_BUF_1五个对象变量。这些生成的类的实例一般都存放在堆 中。堆要对所有类的超类,类的实例进行初始化,同时还要调用类极其每个超类的构架器。而这些操作都是非常消耗系统资源的。因此,对对象的生成进行限制,是 完全有必要的。
- p/ C: s* D) X8 T
5 F( m% E& o8 c! H; L- D 经修改,上面的代码可以用如下的代码来替换。' p4 c$ K" \2 K1 s; o
% U$ B) D2 f) k2 U5 w StringBuffer name=new StringBuffer("HuangWeiFeng");
- O" D0 Q+ M% l9 W: P System.out.println(name.append("is my name.").toString());
7 X% b0 o6 b4 {4 k $ C0 M, d* u( k3 e* t" _6 M
系统将进行如下的操作:8 `9 ^9 t, }# w
' J; S( N- W* @" c( |* F' m& r
(1) 生成新的字符串缓冲变量new StringBuffer(STR_BUF_1);' C& n/ b- t8 z! M6 e1 [0 C* n H
(2) 复制该字符串缓冲变量;
, R' E6 |* [9 D, W* H (3) 加载字符串常量"HuangWeiFeng"(STR_1);% P8 W6 f7 S3 [- ?
(4) 调用字符串缓冲的构架器(Constructor);
+ G6 y4 G7 W9 P5 }1 t6 t7 B (5) 保存该字符串缓冲到数组中(从位置1开始);
0 ^$ G6 Z6 L% Q; g, W5 V* k$ T (6) 从java.io.PrintStream类中得到静态的out变量;
2 q! s; h* o$ Q! n' \ (7) 加载STR_BUF_1;$ l# T$ a# J0 B% W1 Q! V
(8) 加载字符串常量"is my name"(STR_2);& D$ ]' W6 R4 n( P
(9) 以STR_2为参数,调用字符串缓冲(StringBuffer)实例中的append方法;
" d! k$ B) N" L$ ~) H0 n* h0 ^ (10) 对于STR_BUF_1执行toString命令(STR_3);
5 @7 x; |0 n8 [ (11)调用out变量中的println方法,输出结果。
8 W5 M9 l: g0 ?; ?: @8 o " i5 T6 u, x+ ^0 u7 F
由此可以看出,经过改进后的代码只生成了四个对象变量:STR_1,STR_2,STR_3和STR_BUF_1.你可能觉得少生成一个对象不会对程序的 性能有很大的提高。但下面的代码段2的执行速度将是代码段1的2倍。因为代码段1生成了八个对象,而代码段2只生成了四个对象。& H5 L" q4 ~/ X- B! T
. z; _$ b; |" r T3 L# H- m 代码段1:
/ B. B5 F1 L4 t. K! ^ 9 c' F* R8 {; U* [& K: f0 n0 k) L
String name= new StringBuffer("HuangWeiFeng");1 q: g4 {( e- q/ E
name+="is my";
( j/ D9 e5 @4 K! k9 ] name+="name";
0 ?9 r7 a6 o* G! H # P/ l! _/ C3 U; V; U' `
代码段2: J2 e/ [2 r6 v7 Y) v9 H' k. S
$ n2 s0 @7 C/ S StringBuffer name=new StringBuffer("HuangWeiFeng");- K# P4 b) W8 {4 I9 T
name.append("is my");1 K3 w5 Y2 \6 z0 v$ J) `
name.append("name.").toString();
4 o! y" x! m- I* o9 K% {8 d / P# a' [) G; w4 T6 i5 @4 e y
因此,充分的利用JAVA提供的库函数来优化程序,对提高JAVA程序的性能时非常重要的.其注意点主要有如下几方面;
! Y" i/ M, y2 T5 R L
5 ]! j0 P3 H1 ?: s) e (1) 尽可能的使用静态变量(Static Class Variables)8 d% W$ E5 R1 t6 k5 r4 `- h
1 I5 ]* E/ [! S
如果类中的变量不会随他的实例而变化,就可以定义为静态变量,从而使他所有的实例都共享这个变量。* E9 D4 ?; s3 ~! g" o' [
# L7 G8 M. c) @$ H" R8 | 例:
+ R6 Q$ i3 S) A% ^) N8 @ @1 ~7 L! q public class foo# `. R/ g9 I8 h7 K( @& B
{
0 _+ d( n1 b0 ?: z( ^ SomeObject so=new SomeObject();
/ ~- D) H; |, Q; @3 P( n5 K5 e }# E; l' v6 t- L4 I6 J8 R
, w' z z f, ~: W+ ^) s1 P
就可以定义为:
8 R8 k6 {8 S4 y7 Z4 V( x& E' H public class foo% D$ E" F7 d2 h. J
{
9 \9 r+ y5 [ q: t, w8 k- r( ` static SomeObject so=new SomeObject();
m' b" k2 Z7 S' y- K, H0 `( X }! `" d/ q' G4 ^6 ?9 ~" ^
" x+ C/ T1 F5 B% g/ ~6 T7 d6 j8 V
(2) 不要对已生成的对象作过多的改变。
3 _4 s( `/ ~; Z
0 q7 t5 C. K% i- ~% j$ \* T" P } 对于一些类(如:String类)来讲,宁愿在重新生成一个新的对象实例,而不应该修改已经生成的对象实例。$ }6 e8 w. Q+ b9 i+ V
例:* l! f+ X, B9 |& X
String name="Huang";
4 T3 [7 J; Z7 h1 X3 C8 L name="Wei";
& W6 w# Z. d& p" z8 \+ b( D name="Feng";% L) d5 K7 U! R, r+ W5 O" C! D5 }
5 g4 z* c' B/ M7 f 上述代码生成了三个String类型的对象实例。而前两个马上就需要系统进行垃圾回收处理。如果要对字符串进行连接的操作,性能将得更差,因为系统将不得为此生成更多得临时变量,如上例1所示。6 O8 H& \2 L3 L$ G$ \9 e0 a
1 F& b9 G! g6 e% B" Z, o (3) 生成对象时,要分配给它合理的空间和大小JAVA中的很多类都有它的默认的空间分配大小。对于StringBuffer类来讲,默认的分配空间大小是16个字符。如果在程序中使用StringBuffer的空间大小不是16个字符,那么就必须进行正确的初始化。
" a* ?/ i0 y! r4 f$ V9 A
7 c* w# b; f: C. g2 h (4) 避免生成不太使用或生命周期短的对象或变量。对于这种情况,因该定义一个对象缓冲池。以为管理一个对象缓冲池的开销要比频繁的生成和回收对象的开销小的多。
- C$ R& d# L6 K' @4 i , _4 b& ]* i" F( r
(5) 只在对象作用范围内进行初始化。JAVA允许在代码的任何地方定义和初始化对象。这样,就可以只在对象作用的范围内进行初始化。从而节约系统的开销。
" v. c h9 T7 J
; e2 T3 e! a$ }4 B+ i8 x 例:
" Y- m9 C! A* m: g) s SomeObject so=new SomeObject();; R7 }5 l) l# B7 R( h4 k8 `
If(x==1) then% ]5 d' U4 ~7 r2 a
{) |; c8 B2 k9 r4 l1 I
Foo=so.getXX();! \+ q& }' k9 D+ C) d5 ^; [* I
}
/ ~" y$ w" g# C. [' }+ Y# M
- k' b5 W8 f3 y; u9 F I 可以修改为:. P. f, x5 \; Y; H8 U/ v4 V3 e+ K2 c+ M
if(x==1) then
% u9 k, G. I+ O- Q* C a1 Q+ w {
; P5 l5 y% L/ x6 k7 k" T* [6 n SomeObject so=new SomeObject();
& {! B; J1 y' A9 O& } Foo=so.getXX();: E% d6 l; u# E7 p8 R/ y
}
7 n8 G. t! D Y4 a # u5 x ]( F" F) A+ J
2.异常(Exceptions)
3 `% z9 a) f3 Y8 L, ^7 F7 I% z- N ; j1 U" q: p& n
JAVA语言中提供了try/catch来发方便用户捕捉异常,进行异常的处理。但是如果使用不当,也会给JAVA程序的性能带来影响。因此,要注意以下两点:3 q+ k* O: F' O+ O. ~: ~2 L C
# n( {: X5 R/ i: d: l
(1) 避免对应用程序的逻辑使用try/catch" ? L. U8 A9 B/ F8 ~
如果可以用if,while等逻辑语句来处理,那么就尽可能的不用try/catch语句。$ L7 |5 j# A$ l+ _% o
4 k4 \ n- j: q! ] (2) 重用异常- C: C( F% O' P! g
在必须要进行异常的处理时,要尽可能的重用已经存在的异常对象。以为在异常的处理中,生成一个异常对象要消耗掉大部分的时间。1 X) e9 _- e: [1 A) L
6 Q/ B# v5 q0 q. d1 `2 t+ ], R
3. 线程(Threading)
5 W4 C% d" e( B" Y
1 N# _5 V# U2 [8 }8 F4 V9 `7 ^ 一个高性能的应用程序中一般都会用到线程。因为线程能充分利用系统的资源。在其他线程因为等待硬盘或网络读写而 时,程序能继续处理和运行。但是对线程运用不当,也会影响程序的性能。/ ~0 j1 e% m; T, L0 Z
3 X; O2 O* K/ n- n 例2:正确使用Vector类
D9 T( d/ |! {) q( p* |; Y Vector主要用 来保存各种类型的对象(包括相同类型和不同类型的对象)。但是在一些情况下使用会给程序带来性能上的影响。这主要是由Vector类的两个特点所决定的。 第一,Vector提供了线程的安全保护功能。即使Vector类中的许多方法同步。但是如果你已经确认你的应用程序是单线程,这些方法的同步就完全不必 要了。第二,在Vector查找存储的各种对象时,常常要花很多的时间进行类型的匹配。而当这些对象都是同一类型时,这些匹配就完全不必要了。因此,有必 要设计一个单线程的,保存特定类型对象的类或集合来替代Vector类.用来替换的程序如下(StringVector.java):, S) D; w* v5 ^ v
" S. K" J0 j: u" C public class StringVector
2 ~- s) ^, J. s' p" I& \; g7 P {
, q, D9 V( X) f3 w# I: e* p- @4 Q private String [] data;
; i0 I, l) m5 F+ g @* \ private int count;
% \$ \! w( t. E! j public StringVector()4 S+ l( n$ P3 I# v" d R
{
5 @0 U* S. _ }8 N+ m6 \1 }# R9 U# T; i this(10); // default size is 10: Z/ V2 ~ \9 a) R
}1 v, x$ S+ R E u8 W
public StringVector(int initialSize)
* Y5 O9 K& g- p8 ` {
3 c8 I' |. D! {. P data = new String[initialSize];
, F8 t: B" t8 r A* L* ^% E$ e }6 J/ S$ D' P% d0 \
public void add(String str)
, O3 ~- ~* p7 r0 {7 T {
$ ~6 y# I8 i% r1 b$ z // ignore null strings2 K }5 m, M! |9 g- y; ?' ^9 ~" L
if(str == null) { return; }
1 N# |# `' f( J ensureCapacity(count + 1);
! X1 ~- q5 k7 M. F6 g9 |( D* h' T7 C data[count++] = str;
0 O. ~/ E; H% E Y* Z) j }; `7 Y' k7 m" g! \9 t) P \
private void ensureCapacity(int minCapacity)! `1 H# @, T( R2 q; I% G
{
( K) m& E* ]8 e# R6 e$ p7 f* ? int oldCapacity = data.length;
/ U5 P8 T! b* @4 d% Q if (minCapacity > oldCapacity)
, v% v3 d0 `6 K {. Q! p! Z) r5 A }& o% k
String oldData[] = data;6 w @: n0 u7 F6 X- R; Y7 H
int newCapacity = oldCapacity * 2;: G8 J7 X9 ^) M, O
data = new String[newCapacity];) B0 G2 \# R6 p$ e
System.arraycopy(oldData, 0, data, 0, count);+ z- l. f: F5 }! I C
}
* g3 @+ l7 ?4 Z) a. R+ ^/ L }1 B: m6 u, f. V* `) i) ~1 D! v3 d) ]
public void remove(String str)
2 b# ]' z2 J0 ^ R {
2 U) L/ i1 }6 T7 L% O. D if(str == null) { return; // ignore null str }
* X5 X* G2 w( e' f x8 c! b/ l for(int i = 0; i < count; i++)
0 E& ~7 R* }; C7 v z$ q" n; B/ M {
5 Q5 T+ j# w2 K9 z5 D" } // check for a match
+ W9 v* v/ a8 U" z1 M1 Z0 d7 ^ if(data.equals(str)); ~( R/ i8 w* k6 k: | C
{
5 Q0 g" r8 Q( a: r System.arraycopy(data,i+1,data,i,count-1); // copy data8 `; D' E& |, N N
// allow previously valid array element be gc´d
$ i9 D* v3 K/ O/ F data[--count] = null;2 E1 \0 s/ b8 w! c
return;
5 f- n$ m3 w) H( o { }+ A m7 f( g. N+ P& f
}
; \6 x% q+ o2 x' }' } }* ^. g- x0 W$ Z
public final String getStringAt(int index)1 X$ V5 `$ C: O
{% R, o7 _5 T; G+ `- Y, T
if(index < 0) { return null; }) x |' q' z: B3 n5 S7 C( C
else if(index > count) { return null; // index is > # strings }: u- n& r* P+ e/ F: G/ e* }
else { return data[index]; // index is good }1 l1 e3 ~' J$ P0 E; h4 x
}
$ t2 s4 {8 X6 k$ d }
6 L/ |: T" y, r+ S: g
$ ~2 A; L# [5 [- D2 _, E 因此,代码:
" N- @( H( e' p f" P Vector Strings=new Vector();& |" g' O) g/ {
Strings.add("One");! H1 k( _- k) V6 P
Strings.add("Two");6 m& w, \* h3 t+ K, ]* \) q5 r: p
String Second=(String)Strings.elementAt(1);- C0 f8 @! G/ S4 B7 @% G# S( C+ K
4 m4 v# w$ ?; B) B; Y
可以用如下的代码替换:
& {+ c0 C9 a0 o7 C, C6 l8 h StringVector Strings=new StringVector(); V O t4 B+ S3 S6 N4 }, X( E4 J
Strings.add("One");
* y, D5 t+ U$ `) y Strings.add("Two");
- z7 T' ~) l. T, |/ s! p# a# P String Second=Strings.getStringAt(1);
5 E3 R' R& L9 F 这样就可以通过优化线程来提高JAVA程序的性能。用于测试的程序如下(TestCollection.java):
# @+ n* D1 [8 y' x2 y+ o' C , ], p% Q, T3 |; Z- @
import java.util.Vector;: ^7 S4 m# B5 p
public class TestCollection! [$ j( ?2 H& U; l# Q9 x1 y: ]3 K A
{
( f7 C f2 d1 V! p. l. g+ t public static void main(String args []); ^" a0 U; S0 D/ b; s
{% Q4 t1 o# Z0 ]6 P
TestCollection collect = new TestCollection();
3 w5 u! U/ h4 P+ C4 Z ?1 T+ u! q if(args.length == 0)0 D0 U( M1 S! b; v8 r( e5 H$ o
{: E( Y: k! P7 Z+ F2 F$ D1 j( }& _
System.out.println("Usage: java TestCollection [ vector | stringvector ]");
0 v* ~: z* C# S" g6 ?7 V System.exit(1);6 C. |0 u) g2 c/ ?% R
}4 l1 B7 k1 a% ?; E/ b7 h3 w1 \
if(args[0].equals("vector"))* s# ?) N/ q1 l. q x
{
3 g7 u# _2 n( O7 i i5 { Vector store = new Vector();5 \4 ^& p5 ~0 S" U
long start = System.currentTimeMillis();
* M5 X# |, m+ H' F- F for(int i = 0; i < 1000000; i++)
5 u2 Y! S/ e. z1 S' u _+ s {" L4 [$ k r* s1 N j
store.addElement("string");' Q. K5 B# |" V6 K- J
}% `; G: z$ L; \+ s; q
long finish = System.currentTimeMillis();
1 _& o' O0 H. w- O4 h( C) k$ S System.out.println((finish-start));! f/ E* M/ s$ y: K# O
start = System.currentTimeMillis();$ c. u! ]% S. x+ g
for(int i = 0; i < 1000000; i++)
9 Z- M. ]& j$ H( X6 Z( j {
+ M- b6 r8 t O& E String result = (String)store.elementAt(i);5 ]2 U& g) K0 G
}/ ~) }* u% [% L/ {2 W6 Z- @
finish = System.currentTimeMillis();- o; g% S5 b# ~" Z) c, v( T
System.out.println((finish-start));+ P4 `0 p2 K* ^" H
}
. N+ J1 ^# S; h$ C else if(args[0].equals("stringvector"))
' j* P1 e8 V8 V( n {
" U5 j, T9 [9 F7 K2 N+ U StringVector store = new StringVector();' }$ _* s4 g! | ]
long start = System.currentTimeMillis();
1 H( g( i" C4 u2 M for(int i = 0; i < 1000000; i++) { store.add("string"); }
6 Q& X( A1 J! o! }9 X4 e long finish = System.currentTimeMillis();' c2 Q& L( B0 w+ m) M
System.out.println((finish-start));/ |' i1 I( s5 ~5 ?7 R- I& b8 ?& G
start = System.currentTimeMillis();/ h4 I( W1 x1 P
for(int i = 0; i < 1000000; i++) {! j r7 o3 V) O0 q8 l! q3 z
String result = store.getStringAt(i);! u, P2 q6 j, P# I f
}% b. X9 \! t1 G$ c5 Z
finish = System.currentTimeMillis();0 Z+ S$ q; d- e7 U) X5 }+ G' A
System.out.println((finish-start));
. i$ `" \' w; C' _" E }
: B- V$ _1 b/ q9 \! m/ O7 f) J }
: l, k; F' u: |7 A1 ? }8 S q5 k: E) x% Y Z2 W/ y
) Q3 P& c9 p5 O3 B, _3 e 关于线程的操作,要注意如下几个方面:* o" i5 k* n& j, D! y) p5 j' ^
0 x7 \" f* T4 s (1) 防止过多的同步
3 {" k9 p# C% b" c0 p+ [9 e) S: w 如上所示,不必要的同步常常会造成程序性能的下降。因此,如果程序是单线程,则一定不要使用同步。
, ]# [" R1 x: f3 P
& W6 ~) k! J. B" L2 O' }& G3 d (2) 同步方法而不要同步整个代码段* h* l) `+ r" ]
对某个方法或函数进行同步比对整个代码段进行同步的性能要好。* {$ M. F9 s8 W5 e
5 R6 I- t; o# J7 C8 ]5 K) \ (3) 对每个对象使用多”锁”的机制来增大并发。
0 K. v" h5 }/ c! c( \0 m; F c% _ 一般每个对象都只有一个”锁”,这就表明如果两个线程执行一个对象的两个不同的同步方法时,会发生”死锁”。即使这两个方法并不共享任何资源。为了避免这个问题,可以对一个对象实行”多锁”的机制。如下所示:
/ `* O' A, Q0 l! V1 q 8 ?5 Z' u" E" o# \/ u: l
class foo$ ~) f5 E9 Y% |) @: H8 {
{# P% l4 D; Y' i# }( u: r* I
private static int var1;
0 ~ X, t$ V) f9 L. r private static Object lock1=new Object();, I: n% J3 ?! c9 f0 l- D# j3 [
private static int var2;: k' v( r. z: l: B
private static Object lock2=new Object();
) }7 r/ R* E8 `* ]3 ^0 r public static void increment1()- k" |; O) P! v& C% U* k5 A
{, S, a7 W4 r# X
synchronized(lock1)* j1 f1 ~) T- ^
{
6 H) Z% M" w) H7 l4 u+ H var1++;
; w0 s: o/ m; L0 T& V t }
9 D; s- V5 c, j$ Z }
. U8 q+ J; y' F' z5 Q+ g public static void increment2()
8 S3 Z# v1 ~1 A# C# Y {
. G- ^8 T1 g) W+ z' `: b( M synchronized(lock2)+ E1 J1 w( |& T4 P0 M% E
{
$ [5 r" F% F' w) v6 g* P, d' ]4 t var2++;* g. m8 F: L1 z9 I; r( j7 e) p2 c- E; S# K
}
& ]; S" h* h2 L8 i7 n; j+ a# a! a }. N8 d! J2 n5 h: W
}
4 Y2 L9 t4 G, h2 P2 R : W' [" y" p$ I! a
4.输入和输出(I/O)
$ A: h+ Q2 [" S0 r . t$ }/ P8 q V. j8 P
输入和输出包括很多方面,但涉及最多的是对硬盘,网络或数据库的读写操作。对于读写操作,又分为有缓存和没有缓存的;对于数据库的操作,又可以有多种类型的JDBC驱动器可以选择。但无论怎样,都会给程序的性能带来影响。因此,需要注意如下几点:5 l4 f' T, c' t! Y# k/ Q! k5 G1 J& Q
" F, {8 l8 q# R3 e, ~1 F" e* r
(1) 使用输入输出缓冲
- q6 D: w L5 ]3 M 尽可能的多使用缓存。但如果要经常对缓存进行刷新(flush),则建议不要使用缓存。
) ]+ l3 u1 ~& v, M1 V8 Z ' V% b; c, E; P1 [# e$ ?
(2) 输出流(Output Stream)和Unicode字符串" y9 b1 G, b' J- b$ ^
当时用Output Stream和Unicode字符串时,Write类的开销比较大。因为它要实现Unicode到字节(byte)的转换.因此,如果可能的话,在使用Write类之前就实现转换或用OutputStream类代替Writer类来使用。
1 S" i- z3 `7 ^/ F! _ 8 x$ g1 W4 |. x e
(3) 当需序列化时使用transient0 g" Q1 z" Z& k3 N( p' }
当序列化一个类或对象时,对于那些原子类型(atomic)或可以重建的原素要表识为transient类型。这样就不用每一次都进行序列化。如果这些序列化的对象要在网络上传输,这一小小的改变对性能会有很大的提高。3 M3 _5 f2 a; ^. {5 b6 n
1 V w' E, V5 B1 B% `5 g7 `7 ?. f& \# U. S (4) 使用高速缓存(Cache)
$ p; H" @4 o. G( L/ D+ X 对于那些经常要使用而又不大变化的对象或数据,可以把它存储在高速缓存中。这样就可以提高访问的速度。这一点对于从数据库中返回的结果集尤其重要。
+ {1 `: v9 D+ a' K/ r# \
0 {& V# `% U$ A/ I# z (5) 使用速度快的JDBC驱动器(Driver)$ Z' n( C4 d* v/ l0 y
JAVA对访问数据库提供了四种方法。这其中有两种是JDBC驱动器。一种是用JAVA外包的本地驱动器;另一种是完全的JAVA驱动器。具体要使用哪一种得根据JAVA布署的环境和应用程序本身来定。
. T7 }3 S% k; t0 O) W+ J5 Y - @; V4 T! c Y, n) k3 y
5.一些其他的经验和技巧+ L! w" Q6 s- k. ?, M
' a7 P- K$ ] {4 J6 O4 ~
(1) 使用局部变量。
: E, e2 k. i! p (2) 避免在同一个类中动过调用函数或方法(get或set)来设置或调用变量。, h; l" s) U. X0 v0 B
(3) 避免在循环中生成同一个变量或调用同一个函数(参数变量也一样)。! F1 `& L* h# {! A' C; c
(4) 尽可能的使用static,final,private等关键字。) }- X2 f4 i% P6 f
(5) 当复制大量数据时,使用System.arraycopy()命令。
/ q* j) @) q, _8 _& P4 A
下面将提供一些在JAVA程序的设计和编码中,为了能够提高JAVA程序的性能,而经常采用的一些方法和技巧。
- _: K- h5 `( H
. }/ \3 Y i2 k/ a 1.对象的生成和大小的调整。
2 c' G" ~9 i* u$ B1 I6 z9 H
4 X: h+ r+ M, J JAVA程序设计中一个普遍的问题就是没有好好的利用JAVA语言本身提供的函数,从而常常会生成大量的对象(或实例)。由于系统不仅要花时间生成对象,以后可能还需花时间对这些对象进行垃圾回收和处理。因此,生成过多的对象将会给程序的性能带来很大的影响。
; Y- r8 I( c; P4 }$ ^0 ? ! y3 n0 E# _: Z8 O) l
例1:关于String ,StringBuffer,+和append0 h% H3 I- |& k; `
7 J6 D0 n9 T5 m1 V* e JAVA语言提供了对于String类型变量的操作。但如果使用不当,会给程序的性能带来影响。如下面的语句:$ o. _8 M u4 g, S/ `: B: t
3 T% e/ m1 u5 V6 ^/ V: k+ W String name=new String("HuangWeiFeng");
5 z2 z$ C0 Q5 O( p System.out.println(name+"is my name");* y' z5 J4 y9 D' Q
# ~, z0 T- t6 f( L5 h9 M 看似已经很精简了,其实并非如此。为了生成二进制的代码,要进行如下的步骤和操作:
6 u1 Z# c$ M! [ _/ Z0 a2 `' A" g" W
(1) 生成新的字符串 new String(STR_1);
% Y! I( Q, U; G5 i (2) 复制该字符串;
. Y: p% p8 T" P* G6 M6 e Y/ _ (3) 加载字符串常量"HuangWeiFeng"(STR_2);
{9 ^, t- M1 [3 v2 W3 C/ `2 o6 l (4) 调用字符串的构架器(Constructor);" a6 k9 c+ s+ t6 ~: C. P) p
(5) 保存该字符串到数组中(从位置0开始);) Y$ D) N$ Y/ [% D, M- Y
(6) 从java.io.PrintStream类中得到静态的out变量;
" x# n. i( P: V, u; o+ b (7) 生成新的字符串缓冲变量new StringBuffer(STR_BUF_1);
. P( M9 s' w0 }* F7 l1 Y (8) 复制该字符串缓冲变量;4 X( V3 u% M' s7 p
(9) 调用字符串缓冲的构架器(Constructor);
) }4 ?$ N/ C% p" L! [7 V1 |0 L (10) 保存该字符串缓冲到数组中(从位置1开始);
* v# ]6 X0 z8 u/ x (11) 以STR_1为参数,调用字符串缓冲(StringBuffer)类中的append方法;" w9 U3 D$ u7 y
(12) 加载字符串常量"is my name"(STR_3);8 y+ E4 F4 s$ q- K
(13) 以STR_3为参数,调用字符串缓冲(StringBuffer)类中的append方法;) L) f+ Y1 }7 {( r1 R( }, A
(14) 对于STR_BUF_1执行toString命令;
; D; K" G/ X! r9 v/ b (15) 调用out变量中的println方法,输出结果。4 W: x' b' l8 O; p9 n( G* R
* `9 c1 ]0 O8 g' }1 k7 J" S7 G 由此可以看 出,这两行简单的代码,就生成了STR_1,STR_2,STR_3,STR_4和STR_BUF_1五个对象变量。这些生成的类的实例一般都存放在堆 中。堆要对所有类的超类,类的实例进行初始化,同时还要调用类极其每个超类的构架器。而这些操作都是非常消耗系统资源的。因此,对对象的生成进行限制,是 完全有必要的。
- p/ C: s* D) X8 T
5 F( m% E& o8 c! H; L- D 经修改,上面的代码可以用如下的代码来替换。' p4 c$ K" \2 K1 s; o
% U$ B) D2 f) k2 U5 w StringBuffer name=new StringBuffer("HuangWeiFeng");
- O" D0 Q+ M% l9 W: P System.out.println(name.append("is my name.").toString());
7 X% b0 o6 b4 {4 k $ C0 M, d* u( k3 e* t" _6 M
系统将进行如下的操作:8 `9 ^9 t, }# w
' J; S( N- W* @" c( |* F' m& r
(1) 生成新的字符串缓冲变量new StringBuffer(STR_BUF_1);' C& n/ b- t8 z! M6 e1 [0 C* n H
(2) 复制该字符串缓冲变量;
, R' E6 |* [9 D, W* H (3) 加载字符串常量"HuangWeiFeng"(STR_1);% P8 W6 f7 S3 [- ?
(4) 调用字符串缓冲的构架器(Constructor);
+ G6 y4 G7 W9 P5 }1 t6 t7 B (5) 保存该字符串缓冲到数组中(从位置1开始);
0 ^$ G6 Z6 L% Q; g, W5 V* k$ T (6) 从java.io.PrintStream类中得到静态的out变量;
2 q! s; h* o$ Q! n' \ (7) 加载STR_BUF_1;$ l# T$ a# J0 B% W1 Q! V
(8) 加载字符串常量"is my name"(STR_2);& D$ ]' W6 R4 n( P
(9) 以STR_2为参数,调用字符串缓冲(StringBuffer)实例中的append方法;
" d! k$ B) N" L$ ~) H0 n* h0 ^ (10) 对于STR_BUF_1执行toString命令(STR_3);
5 @7 x; |0 n8 [ (11)调用out变量中的println方法,输出结果。
8 W5 M9 l: g0 ?; ?: @8 o " i5 T6 u, x+ ^0 u7 F
由此可以看出,经过改进后的代码只生成了四个对象变量:STR_1,STR_2,STR_3和STR_BUF_1.你可能觉得少生成一个对象不会对程序的 性能有很大的提高。但下面的代码段2的执行速度将是代码段1的2倍。因为代码段1生成了八个对象,而代码段2只生成了四个对象。& H5 L" q4 ~/ X- B! T
. z; _$ b; |" r T3 L# H- m 代码段1:
/ B. B5 F1 L4 t. K! ^ 9 c' F* R8 {; U* [& K: f0 n0 k) L
String name= new StringBuffer("HuangWeiFeng");1 q: g4 {( e- q/ E
name+="is my";
( j/ D9 e5 @4 K! k9 ] name+="name";
0 ?9 r7 a6 o* G! H # P/ l! _/ C3 U; V; U' `
代码段2: J2 e/ [2 r6 v7 Y) v9 H' k. S
$ n2 s0 @7 C/ S StringBuffer name=new StringBuffer("HuangWeiFeng");- K# P4 b) W8 {4 I9 T
name.append("is my");1 K3 w5 Y2 \6 z0 v$ J) `
name.append("name.").toString();
4 o! y" x! m- I* o9 K% {8 d / P# a' [) G; w4 T6 i5 @4 e y
因此,充分的利用JAVA提供的库函数来优化程序,对提高JAVA程序的性能时非常重要的.其注意点主要有如下几方面;
! Y" i/ M, y2 T5 R L
5 ]! j0 P3 H1 ?: s) e (1) 尽可能的使用静态变量(Static Class Variables)8 d% W$ E5 R1 t6 k5 r4 `- h
1 I5 ]* E/ [! S
如果类中的变量不会随他的实例而变化,就可以定义为静态变量,从而使他所有的实例都共享这个变量。* E9 D4 ?; s3 ~! g" o' [
# L7 G8 M. c) @$ H" R8 | 例:
+ R6 Q$ i3 S) A% ^) N8 @ @1 ~7 L! q public class foo# `. R/ g9 I8 h7 K( @& B
{
0 _+ d( n1 b0 ?: z( ^ SomeObject so=new SomeObject();
/ ~- D) H; |, Q; @3 P( n5 K5 e }# E; l' v6 t- L4 I6 J8 R
, w' z z f, ~: W+ ^) s1 P
就可以定义为:
8 R8 k6 {8 S4 y7 Z4 V( x& E' H public class foo% D$ E" F7 d2 h. J
{
9 \9 r+ y5 [ q: t, w8 k- r( ` static SomeObject so=new SomeObject();
m' b" k2 Z7 S' y- K, H0 `( X }! `" d/ q' G4 ^6 ?9 ~" ^
" x+ C/ T1 F5 B% g/ ~6 T7 d6 j8 V
(2) 不要对已生成的对象作过多的改变。
3 _4 s( `/ ~; Z
0 q7 t5 C. K% i- ~% j$ \* T" P } 对于一些类(如:String类)来讲,宁愿在重新生成一个新的对象实例,而不应该修改已经生成的对象实例。$ }6 e8 w. Q+ b9 i+ V
例:* l! f+ X, B9 |& X
String name="Huang";
4 T3 [7 J; Z7 h1 X3 C8 L name="Wei";
& W6 w# Z. d& p" z8 \+ b( D name="Feng";% L) d5 K7 U! R, r+ W5 O" C! D5 }
5 g4 z* c' B/ M7 f 上述代码生成了三个String类型的对象实例。而前两个马上就需要系统进行垃圾回收处理。如果要对字符串进行连接的操作,性能将得更差,因为系统将不得为此生成更多得临时变量,如上例1所示。6 O8 H& \2 L3 L$ G$ \9 e0 a
1 F& b9 G! g6 e% B" Z, o (3) 生成对象时,要分配给它合理的空间和大小JAVA中的很多类都有它的默认的空间分配大小。对于StringBuffer类来讲,默认的分配空间大小是16个字符。如果在程序中使用StringBuffer的空间大小不是16个字符,那么就必须进行正确的初始化。
" a* ?/ i0 y! r4 f$ V9 A
7 c* w# b; f: C. g2 h (4) 避免生成不太使用或生命周期短的对象或变量。对于这种情况,因该定义一个对象缓冲池。以为管理一个对象缓冲池的开销要比频繁的生成和回收对象的开销小的多。
- C$ R& d# L6 K' @4 i , _4 b& ]* i" F( r
(5) 只在对象作用范围内进行初始化。JAVA允许在代码的任何地方定义和初始化对象。这样,就可以只在对象作用的范围内进行初始化。从而节约系统的开销。
" v. c h9 T7 J
; e2 T3 e! a$ }4 B+ i8 x 例:
" Y- m9 C! A* m: g) s SomeObject so=new SomeObject();; R7 }5 l) l# B7 R( h4 k8 `
If(x==1) then% ]5 d' U4 ~7 r2 a
{) |; c8 B2 k9 r4 l1 I
Foo=so.getXX();! \+ q& }' k9 D+ C) d5 ^; [* I
}
/ ~" y$ w" g# C. [' }+ Y# M
- k' b5 W8 f3 y; u9 F I 可以修改为:. P. f, x5 \; Y; H8 U/ v4 V3 e+ K2 c+ M
if(x==1) then
% u9 k, G. I+ O- Q* C a1 Q+ w {
; P5 l5 y% L/ x6 k7 k" T* [6 n SomeObject so=new SomeObject();
& {! B; J1 y' A9 O& } Foo=so.getXX();: E% d6 l; u# E7 p8 R/ y
}
7 n8 G. t! D Y4 a # u5 x ]( F" F) A+ J
2.异常(Exceptions)
3 `% z9 a) f3 Y8 L, ^7 F7 I% z- N ; j1 U" q: p& n
JAVA语言中提供了try/catch来发方便用户捕捉异常,进行异常的处理。但是如果使用不当,也会给JAVA程序的性能带来影响。因此,要注意以下两点:3 q+ k* O: F' O+ O. ~: ~2 L C
# n( {: X5 R/ i: d: l
(1) 避免对应用程序的逻辑使用try/catch" ? L. U8 A9 B/ F8 ~
如果可以用if,while等逻辑语句来处理,那么就尽可能的不用try/catch语句。$ L7 |5 j# A$ l+ _% o
4 k4 \ n- j: q! ] (2) 重用异常- C: C( F% O' P! g
在必须要进行异常的处理时,要尽可能的重用已经存在的异常对象。以为在异常的处理中,生成一个异常对象要消耗掉大部分的时间。1 X) e9 _- e: [1 A) L
6 Q/ B# v5 q0 q. d1 `2 t+ ], R
3. 线程(Threading)
5 W4 C% d" e( B" Y
1 N# _5 V# U2 [8 }8 F4 V9 `7 ^ 一个高性能的应用程序中一般都会用到线程。因为线程能充分利用系统的资源。在其他线程因为等待硬盘或网络读写而 时,程序能继续处理和运行。但是对线程运用不当,也会影响程序的性能。/ ~0 j1 e% m; T, L0 Z
3 X; O2 O* K/ n- n 例2:正确使用Vector类
D9 T( d/ |! {) q( p* |; Y Vector主要用 来保存各种类型的对象(包括相同类型和不同类型的对象)。但是在一些情况下使用会给程序带来性能上的影响。这主要是由Vector类的两个特点所决定的。 第一,Vector提供了线程的安全保护功能。即使Vector类中的许多方法同步。但是如果你已经确认你的应用程序是单线程,这些方法的同步就完全不必 要了。第二,在Vector查找存储的各种对象时,常常要花很多的时间进行类型的匹配。而当这些对象都是同一类型时,这些匹配就完全不必要了。因此,有必 要设计一个单线程的,保存特定类型对象的类或集合来替代Vector类.用来替换的程序如下(StringVector.java):, S) D; w* v5 ^ v
" S. K" J0 j: u" C public class StringVector
2 ~- s) ^, J. s' p" I& \; g7 P {
, q, D9 V( X) f3 w# I: e* p- @4 Q private String [] data;
; i0 I, l) m5 F+ g @* \ private int count;
% \$ \! w( t. E! j public StringVector()4 S+ l( n$ P3 I# v" d R
{
5 @0 U* S. _ }8 N+ m6 \1 }# R9 U# T; i this(10); // default size is 10: Z/ V2 ~ \9 a) R
}1 v, x$ S+ R E u8 W
public StringVector(int initialSize)
* Y5 O9 K& g- p8 ` {
3 c8 I' |. D! {. P data = new String[initialSize];
, F8 t: B" t8 r A* L* ^% E$ e }6 J/ S$ D' P% d0 \
public void add(String str)
, O3 ~- ~* p7 r0 {7 T {
$ ~6 y# I8 i% r1 b$ z // ignore null strings2 K }5 m, M! |9 g- y; ?' ^9 ~" L
if(str == null) { return; }
1 N# |# `' f( J ensureCapacity(count + 1);
! X1 ~- q5 k7 M. F6 g9 |( D* h' T7 C data[count++] = str;
0 O. ~/ E; H% E Y* Z) j }; `7 Y' k7 m" g! \9 t) P \
private void ensureCapacity(int minCapacity)! `1 H# @, T( R2 q; I% G
{
( K) m& E* ]8 e# R6 e$ p7 f* ? int oldCapacity = data.length;
/ U5 P8 T! b* @4 d% Q if (minCapacity > oldCapacity)
, v% v3 d0 `6 K {. Q! p! Z) r5 A }& o% k
String oldData[] = data;6 w @: n0 u7 F6 X- R; Y7 H
int newCapacity = oldCapacity * 2;: G8 J7 X9 ^) M, O
data = new String[newCapacity];) B0 G2 \# R6 p$ e
System.arraycopy(oldData, 0, data, 0, count);+ z- l. f: F5 }! I C
}
* g3 @+ l7 ?4 Z) a. R+ ^/ L }1 B: m6 u, f. V* `) i) ~1 D! v3 d) ]
public void remove(String str)
2 b# ]' z2 J0 ^ R {
2 U) L/ i1 }6 T7 L% O. D if(str == null) { return; // ignore null str }
* X5 X* G2 w( e' f x8 c! b/ l for(int i = 0; i < count; i++)
0 E& ~7 R* }; C7 v z$ q" n; B/ M {
5 Q5 T+ j# w2 K9 z5 D" } // check for a match
+ W9 v* v/ a8 U" z1 M1 Z0 d7 ^ if(data.equals(str)); ~( R/ i8 w* k6 k: | C
{
5 Q0 g" r8 Q( a: r System.arraycopy(data,i+1,data,i,count-1); // copy data8 `; D' E& |, N N
// allow previously valid array element be gc´d
$ i9 D* v3 K/ O/ F data[--count] = null;2 E1 \0 s/ b8 w! c
return;
5 f- n$ m3 w) H( o { }+ A m7 f( g. N+ P& f
}
; \6 x% q+ o2 x' }' } }* ^. g- x0 W$ Z
public final String getStringAt(int index)1 X$ V5 `$ C: O
{% R, o7 _5 T; G+ `- Y, T
if(index < 0) { return null; }) x |' q' z: B3 n5 S7 C( C
else if(index > count) { return null; // index is > # strings }: u- n& r* P+ e/ F: G/ e* }
else { return data[index]; // index is good }1 l1 e3 ~' J$ P0 E; h4 x
}
$ t2 s4 {8 X6 k$ d }
6 L/ |: T" y, r+ S: g
$ ~2 A; L# [5 [- D2 _, E 因此,代码:
" N- @( H( e' p f" P Vector Strings=new Vector();& |" g' O) g/ {
Strings.add("One");! H1 k( _- k) V6 P
Strings.add("Two");6 m& w, \* h3 t+ K, ]* \) q5 r: p
String Second=(String)Strings.elementAt(1);- C0 f8 @! G/ S4 B7 @% G# S( C+ K
4 m4 v# w$ ?; B) B; Y
可以用如下的代码替换:
& {+ c0 C9 a0 o7 C, C6 l8 h StringVector Strings=new StringVector(); V O t4 B+ S3 S6 N4 }, X( E4 J
Strings.add("One");
* y, D5 t+ U$ `) y Strings.add("Two");
- z7 T' ~) l. T, |/ s! p# a# P String Second=Strings.getStringAt(1);
5 E3 R' R& L9 F 这样就可以通过优化线程来提高JAVA程序的性能。用于测试的程序如下(TestCollection.java):
# @+ n* D1 [8 y' x2 y+ o' C , ], p% Q, T3 |; Z- @
import java.util.Vector;: ^7 S4 m# B5 p
public class TestCollection! [$ j( ?2 H& U; l# Q9 x1 y: ]3 K A
{
( f7 C f2 d1 V! p. l. g+ t public static void main(String args []); ^" a0 U; S0 D/ b; s
{% Q4 t1 o# Z0 ]6 P
TestCollection collect = new TestCollection();
3 w5 u! U/ h4 P+ C4 Z ?1 T+ u! q if(args.length == 0)0 D0 U( M1 S! b; v8 r( e5 H$ o
{: E( Y: k! P7 Z+ F2 F$ D1 j( }& _
System.out.println("Usage: java TestCollection [ vector | stringvector ]");
0 v* ~: z* C# S" g6 ?7 V System.exit(1);6 C. |0 u) g2 c/ ?% R
}4 l1 B7 k1 a% ?; E/ b7 h3 w1 \
if(args[0].equals("vector"))* s# ?) N/ q1 l. q x
{
3 g7 u# _2 n( O7 i i5 { Vector store = new Vector();5 \4 ^& p5 ~0 S" U
long start = System.currentTimeMillis();
* M5 X# |, m+ H' F- F for(int i = 0; i < 1000000; i++)
5 u2 Y! S/ e. z1 S' u _+ s {" L4 [$ k r* s1 N j
store.addElement("string");' Q. K5 B# |" V6 K- J
}% `; G: z$ L; \+ s; q
long finish = System.currentTimeMillis();
1 _& o' O0 H. w- O4 h( C) k$ S System.out.println((finish-start));! f/ E* M/ s$ y: K# O
start = System.currentTimeMillis();$ c. u! ]% S. x+ g
for(int i = 0; i < 1000000; i++)
9 Z- M. ]& j$ H( X6 Z( j {
+ M- b6 r8 t O& E String result = (String)store.elementAt(i);5 ]2 U& g) K0 G
}/ ~) }* u% [% L/ {2 W6 Z- @
finish = System.currentTimeMillis();- o; g% S5 b# ~" Z) c, v( T
System.out.println((finish-start));+ P4 `0 p2 K* ^" H
}
. N+ J1 ^# S; h$ C else if(args[0].equals("stringvector"))
' j* P1 e8 V8 V( n {
" U5 j, T9 [9 F7 K2 N+ U StringVector store = new StringVector();' }$ _* s4 g! | ]
long start = System.currentTimeMillis();
1 H( g( i" C4 u2 M for(int i = 0; i < 1000000; i++) { store.add("string"); }
6 Q& X( A1 J! o! }9 X4 e long finish = System.currentTimeMillis();' c2 Q& L( B0 w+ m) M
System.out.println((finish-start));/ |' i1 I( s5 ~5 ?7 R- I& b8 ?& G
start = System.currentTimeMillis();/ h4 I( W1 x1 P
for(int i = 0; i < 1000000; i++) {! j r7 o3 V) O0 q8 l! q3 z
String result = store.getStringAt(i);! u, P2 q6 j, P# I f
}% b. X9 \! t1 G$ c5 Z
finish = System.currentTimeMillis();0 Z+ S$ q; d- e7 U) X5 }+ G' A
System.out.println((finish-start));
. i$ `" \' w; C' _" E }
: B- V$ _1 b/ q9 \! m/ O7 f) J }
: l, k; F' u: |7 A1 ? }8 S q5 k: E) x% Y Z2 W/ y
) Q3 P& c9 p5 O3 B, _3 e 关于线程的操作,要注意如下几个方面:* o" i5 k* n& j, D! y) p5 j' ^
0 x7 \" f* T4 s (1) 防止过多的同步
3 {" k9 p# C% b" c0 p+ [9 e) S: w 如上所示,不必要的同步常常会造成程序性能的下降。因此,如果程序是单线程,则一定不要使用同步。
, ]# [" R1 x: f3 P
& W6 ~) k! J. B" L2 O' }& G3 d (2) 同步方法而不要同步整个代码段* h* l) `+ r" ]
对某个方法或函数进行同步比对整个代码段进行同步的性能要好。* {$ M. F9 s8 W5 e
5 R6 I- t; o# J7 C8 ]5 K) \ (3) 对每个对象使用多”锁”的机制来增大并发。
0 K. v" h5 }/ c! c( \0 m; F c% _ 一般每个对象都只有一个”锁”,这就表明如果两个线程执行一个对象的两个不同的同步方法时,会发生”死锁”。即使这两个方法并不共享任何资源。为了避免这个问题,可以对一个对象实行”多锁”的机制。如下所示:
/ `* O' A, Q0 l! V1 q 8 ?5 Z' u" E" o# \/ u: l
class foo$ ~) f5 E9 Y% |) @: H8 {
{# P% l4 D; Y' i# }( u: r* I
private static int var1;
0 ~ X, t$ V) f9 L. r private static Object lock1=new Object();, I: n% J3 ?! c9 f0 l- D# j3 [
private static int var2;: k' v( r. z: l: B
private static Object lock2=new Object();
) }7 r/ R* E8 `* ]3 ^0 r public static void increment1()- k" |; O) P! v& C% U* k5 A
{, S, a7 W4 r# X
synchronized(lock1)* j1 f1 ~) T- ^
{
6 H) Z% M" w) H7 l4 u+ H var1++;
; w0 s: o/ m; L0 T& V t }
9 D; s- V5 c, j$ Z }
. U8 q+ J; y' F' z5 Q+ g public static void increment2()
8 S3 Z# v1 ~1 A# C# Y {
. G- ^8 T1 g) W+ z' `: b( M synchronized(lock2)+ E1 J1 w( |& T4 P0 M% E
{
$ [5 r" F% F' w) v6 g* P, d' ]4 t var2++;* g. m8 F: L1 z9 I; r( j7 e) p2 c- E; S# K
}
& ]; S" h* h2 L8 i7 n; j+ a# a! a }. N8 d! J2 n5 h: W
}
4 Y2 L9 t4 G, h2 P2 R : W' [" y" p$ I! a
4.输入和输出(I/O)
$ A: h+ Q2 [" S0 r . t$ }/ P8 q V. j8 P
输入和输出包括很多方面,但涉及最多的是对硬盘,网络或数据库的读写操作。对于读写操作,又分为有缓存和没有缓存的;对于数据库的操作,又可以有多种类型的JDBC驱动器可以选择。但无论怎样,都会给程序的性能带来影响。因此,需要注意如下几点:5 l4 f' T, c' t! Y# k/ Q! k5 G1 J& Q
" F, {8 l8 q# R3 e, ~1 F" e* r
(1) 使用输入输出缓冲
- q6 D: w L5 ]3 M 尽可能的多使用缓存。但如果要经常对缓存进行刷新(flush),则建议不要使用缓存。
) ]+ l3 u1 ~& v, M1 V8 Z ' V% b; c, E; P1 [# e$ ?
(2) 输出流(Output Stream)和Unicode字符串" y9 b1 G, b' J- b$ ^
当时用Output Stream和Unicode字符串时,Write类的开销比较大。因为它要实现Unicode到字节(byte)的转换.因此,如果可能的话,在使用Write类之前就实现转换或用OutputStream类代替Writer类来使用。
1 S" i- z3 `7 ^/ F! _ 8 x$ g1 W4 |. x e
(3) 当需序列化时使用transient0 g" Q1 z" Z& k3 N( p' }
当序列化一个类或对象时,对于那些原子类型(atomic)或可以重建的原素要表识为transient类型。这样就不用每一次都进行序列化。如果这些序列化的对象要在网络上传输,这一小小的改变对性能会有很大的提高。3 M3 _5 f2 a; ^. {5 b6 n
1 V w' E, V5 B1 B% `5 g7 `7 ?. f& \# U. S (4) 使用高速缓存(Cache)
$ p; H" @4 o. G( L/ D+ X 对于那些经常要使用而又不大变化的对象或数据,可以把它存储在高速缓存中。这样就可以提高访问的速度。这一点对于从数据库中返回的结果集尤其重要。
+ {1 `: v9 D+ a' K/ r# \
0 {& V# `% U$ A/ I# z (5) 使用速度快的JDBC驱动器(Driver)$ Z' n( C4 d* v/ l0 y
JAVA对访问数据库提供了四种方法。这其中有两种是JDBC驱动器。一种是用JAVA外包的本地驱动器;另一种是完全的JAVA驱动器。具体要使用哪一种得根据JAVA布署的环境和应用程序本身来定。
. T7 }3 S% k; t0 O) W+ J5 Y - @; V4 T! c Y, n) k3 y
5.一些其他的经验和技巧+ L! w" Q6 s- k. ?, M
' a7 P- K$ ] {4 J6 O4 ~
(1) 使用局部变量。
: E, e2 k. i! p (2) 避免在同一个类中动过调用函数或方法(get或set)来设置或调用变量。, h; l" s) U. X0 v0 B
(3) 避免在循环中生成同一个变量或调用同一个函数(参数变量也一样)。! F1 `& L* h# {! A' C; c
(4) 尽可能的使用static,final,private等关键字。) }- X2 f4 i% P6 f
(5) 当复制大量数据时,使用System.arraycopy()命令。
发表评论
-
Eclipse很卡的解决方法
2016-04-13 15:03 566配置eclipse.ini文件,可以根据内存大小视情况而定 ... -
shell 跟java 相互调用和获取结果
2011-11-08 15:16 3041被调用的shell a.sh #!/bin/bash e ... -
关于日文编码(Shift_JIS Windows-31 EUC-JP)
2011-03-02 09:50 156451、常用编码 日语的文字编码主要是Shift_JIS、EUC ... -
ITEXT 使用小结
2010-07-21 15:13 1620最近项目中使用到IText5,其实跟之前版本并无特殊差别, ... -
Java 1.5 小手册 Cheat Sheet
2009-12-26 19:07 1078Create a new object instance S ... -
SpringSide 3.2.1 寒冬日志版发布
2009-12-24 22:54 1225最近国内的开源项目非常生猛,与Play!Framework有 ... -
使用HttpComponents获取整个页面的内容
2009-12-14 11:52 2724commons-httpclient已经不再更新了, htt ... -
weblogic11集群之建立节点信任
2009-11-24 14:56 21711、管理server和被管server的domain名字必须一 ... -
体验一下JBOSSESB The Hello World QuickStart
2009-11-16 17:26 16691)跑到 http://www.jboss.org/jboss ... -
过滤器中向所有JSP页面插入html代码
2009-10-28 16:06 2356为公司内部开发了1个简单的MVC框架,框架中需要向所有JSP页 ... -
GlassFish替换Tomcat
2009-09-29 09:34 12111. GlassFish替换Tomcat背景 ... -
禁止apache和tomcat列出目录清单的方法
2009-09-28 16:49 2223如果用户uri中没有指定文件名,apache和tomcat在默 ... -
关于apache和tomcat的连接器
2009-09-28 16:28 1480mod_jk2确实很烂。 几天的mod_jk2的云山雾罩之后 ... -
Linux下Tomcat与Apache Web服务器的整合
2009-09-28 16:21 10291、引言 基 ... -
有关使用和部署 Java 持久性体系结构 (JPA) 的案例研究
2009-04-24 17:19 10942006 年夏天发布的 EJB 3 ... -
Spring AOP原理解析
2009-04-24 15:07 10282AOP概念: 实现AOP有两种 ... -
spring aop的原理
2009-04-24 15:06 2808AOP概念 让我们从定义一些重要的AOP概念开始。 — 方 ... -
struts2的struts.properties配置文件详解
2009-04-23 16:34 978struts.action.extension ... -
详解JRE和JDK的区别
2009-02-04 11:07 1436JDK JDK 是整个Java的核心,包括了Java运行环境 ... -
jdk和jre的区别
2009-02-04 11:06 1965对于java初学者来说,往往不懂区分jdk和jre的区别,实际 ...
相关推荐
《Java程序性能优化:让你的Java程序更快、更稳定》以Java性能调优为主线,系统地阐述了与Java性能优化相关的知识与技巧。 《Java程序性能优化:让你的Java程序更快、更稳定》共6章,先后从软件设计、软件编码、...
《Java程序性能优化:让你的Java程序更快、更稳定》以Java性能调优为主线,系统地阐述了与Java性能优化相关的知识与技巧。《Java程序性能优化:让你的Java程序更快、更稳定》共6章,先后从软件设计、软件编码、JVM调优...
《Java程序性能优化》这本书主要探讨了如何通过各种技术和策略来提高Java应用程序的性能。 ### 性能瓶颈分析 - **CPU使用率高**:程序执行时,某些部分可能过度消耗CPU资源,导致性能下降。 - **内存泄漏**:对象...
在本文中,我们将深入探讨Java性能优化的关键点,帮助你的Java程序达到更快、更稳定的目标。 1. **JVM调优**:Java虚拟机(JVM)是Java程序运行的基础,优化JVM参数可以显著提升性能。例如,调整堆内存大小(-Xms和-...
总的来说,“Java程序性能优化 让你的Java程序更快、更稳定”这本书将涵盖以上诸多方面,通过理论结合实际的示例代码,帮助读者深入理解Java性能优化的各个方面,从而写出更快、更稳定的Java程序。书中附带的源文件...
Java程序性能优化是每个开发人员都需要关注的重要领域,特别是在企业级应用中,高效稳定的Java程序能够带来显著的业务优势。本资源包含一个PDF文档和相关的视频教程,旨在帮助你提升Java程序的速度和稳定性。 首先...
### JAVA程序性能优化 在Java开发中,程序性能优化是一个重要的环节,它直接影响到应用程序的运行效率、用户体验以及系统的整体稳定性。本文将基于提供的标题、描述及部分内容,深入探讨几个关键性的性能优化策略。...
一个优秀的程序员,不仅要会编写程序,更要会编写高质量的程序,感受Java开发中的大智慧,让你的Java程序更优美 专注于Java应用程序的优化方法、技巧和思想,深入剖析软件设计层面、代码层面、JVM虚拟机层面的优化...
《Java程序性能优化》是葛一鸣在2012年10月出版的第一版专著,这本书深入探讨了如何提升Java应用程序的运行效率和性能。在Java开发中,性能优化是一个关键领域,它涉及到代码的高效编写、内存管理、线程调度、数据库...
Java程序性能优化是每个开发人员都需要关注的重要领域,特别是在企业级应用中,高效的代码执行能够带来更好的用户体验,减少服务器资源的消耗,降低运营成本。本资料包“Java程序性能优化 让你的Java程序更快、更...
性能优化手册是一套java性能学习研究小技巧,包含内容:Java性能优化、JVM性能优化、服务器性能优化、数据库性能优化、前端性能优化等。 内容包括但不限于: String 性能优化的 3 个小技巧 HashMap 7 种遍历方式...
《Java程序性能优化:让你的Java程序更快、更稳定》以Java性能调优为主线,系统地阐述了与Java性能优化相关的知识与技巧。 《Java程序性能优化:让你的Java程序更快、更稳定》共6章,先后从软件设计、软件编码、JVM...