java中的位運(yùn)算資料_第1頁
java中的位運(yùn)算資料_第2頁
java中的位運(yùn)算資料_第3頁
java中的位運(yùn)算資料_第4頁
java中的位運(yùn)算資料_第5頁
已閱讀5頁,還剩25頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

JAVA的位運(yùn)算

關(guān)鍵字:java位運(yùn)算

Java位運(yùn)算

一,Java位運(yùn)算

1.表示方法:

在Java語言中,二進(jìn)制數(shù)使用補(bǔ)碼表示,最高位為符號(hào)位,正數(shù)的符號(hào)位為

0,負(fù)數(shù)為1。補(bǔ)碼的表示需要滿足如下要求。

⑴正數(shù)的最高位為0,其余各位代表數(shù)值本身(二進(jìn)制數(shù))。

(2)對(duì)于負(fù)數(shù),通過對(duì)該數(shù)絕對(duì)值的補(bǔ)碼按位取反,再對(duì)整個(gè)數(shù)加1。

2.位運(yùn)算符

位運(yùn)算表達(dá)式由操作數(shù)和位運(yùn)算符組成,實(shí)現(xiàn)對(duì)整數(shù)類型的二進(jìn)制數(shù)進(jìn)行位運(yùn)

算。位運(yùn)算符可以分為邏輯運(yùn)算符(包括[&、I和D及移位運(yùn)算符(包括〉、?

和>>>)。

注釋廣

?是取反運(yùn)算

首先,你要知道java中的int是32位的

其次,正數(shù)以原碼的形式存儲(chǔ),負(fù)數(shù)以補(bǔ)碼的形式存儲(chǔ)

4的二進(jìn)制是00000000000000000000000000000100

取反后得11111111111111111111111111111011

java中都是有符號(hào)數(shù),首位是1,所以是負(fù)數(shù),負(fù)數(shù)也就是補(bǔ)碼,也就是說

11111111111111111111111111111011是補(bǔ)碼

補(bǔ)碼,反碼加1后得源碼

轉(zhuǎn)換成源碼得00000000000000000000000000000101

這個(gè)數(shù)是5,加上符號(hào)就是?5

1)左移位運(yùn)竟符(<<)能將運(yùn)兌符左邊的運(yùn)算對(duì)象向左移動(dòng)運(yùn)算符右側(cè)指定的位

數(shù)(在低位補(bǔ)0)。

2)“有符號(hào)”右移位運(yùn)算符(>>)則將運(yùn)算符左邊的運(yùn)算對(duì)象向右移動(dòng)運(yùn)算符右

側(cè)指定的位數(shù)。

“有符號(hào)”右移位運(yùn)算符使用了“符號(hào)擴(kuò)展”:若值為正,則在高位插入0;若

值為負(fù),則在高位插入1。

3)Java也添加了一種“無符號(hào)”右移位運(yùn)算符(>>>),它使用了“零擴(kuò)展”:

無論正負(fù),都在高位插入0。這一運(yùn)算符是C或C++沒有的。

4)若對(duì)char,byte或者short進(jìn)行移位處理,那么在移位進(jìn)行之前,它們會(huì)自

動(dòng)轉(zhuǎn)換成一個(gè)int。

只有右側(cè)的5個(gè)低位才會(huì)用到。這樣可防止我們?cè)谝粋€(gè)int數(shù)里移動(dòng)不切實(shí)際的

位數(shù)。

若對(duì)一個(gè)long值進(jìn)行處理,最后得到的結(jié)果也是long。此時(shí)只會(huì)用到右側(cè)的6

個(gè)低位,防止移動(dòng)超過long值里現(xiàn)成的位數(shù)。

但在進(jìn)行“無符號(hào)”右移位時(shí),也可能遇到一個(gè)問題。若對(duì)byte或short值進(jìn)

行右移位運(yùn)算,得到的可能不是正確的結(jié)果(Java1.0和Java1.1特別突出)。

它們會(huì)自動(dòng)轉(zhuǎn)換成int類型,并進(jìn)行右移位。但“零擴(kuò)展”不會(huì)發(fā)生,所以在那

些情況下會(huì)得到-1的結(jié)果。

在進(jìn)行位運(yùn)算時(shí),需要注意以下幾點(diǎn)。

(1)>>>和〉的區(qū)別是:在執(zhí)行運(yùn)算時(shí),>>>運(yùn)算符的操作數(shù)高位補(bǔ)0,而>>運(yùn)算

符的操作數(shù)高位移入原來高位的值。

⑵右移一位相當(dāng)于除以2,左移一位(在不溢出的情況下)相當(dāng)于乘以2;移位運(yùn)

算速度高于乘除運(yùn)算。

(3)若進(jìn)行位邏輯運(yùn)算的兩個(gè)操作數(shù)的數(shù)據(jù)長(zhǎng)度不相同,則返回值應(yīng)該是數(shù)據(jù)長(zhǎng)

度較長(zhǎng)的數(shù)據(jù)類型。

(4)按位異或可以不使用臨時(shí)變量完成兩個(gè)值的交換,也可以使某個(gè)整型數(shù)的特

定位的值翻轉(zhuǎn)。

(5)按位與運(yùn)算可以用來屏蔽特定的位,也可以用來取某個(gè)數(shù)型數(shù)中某些特定的

位。

⑹按位或運(yùn)算可以用來對(duì)某個(gè)整型數(shù)的特定位的值置lo

3.位運(yùn)算符的優(yōu)先級(jí)

~的優(yōu)先級(jí)最高,其次是《、>>和>>>,再次是&,然后是"優(yōu)先級(jí)最低的是|。

二,按位異或運(yùn)算符”

參與運(yùn)算的兩個(gè)值,如果兩個(gè)相應(yīng)位相同,則結(jié)果為0,否則為1。即:0^0=0,

1^0=1,0^1=1,1^1=0

例如:ioiooooroooioooi=ionoooo

0^0=0,0^1=10異或任何數(shù)=任何數(shù)

ro=i,ri=oi異或任何數(shù)一任何數(shù)取反

任何數(shù)異或自己=把自己置o

(1)按位異或可以用來使某些特定的位翻轉(zhuǎn),如對(duì)數(shù)10100001的第2位和第3

位翻轉(zhuǎn),可以將數(shù)與00000110進(jìn)行按位異或運(yùn)算。

1010000r00000110=10100111//10100001八0x06=1010

0001-6

(2)通過按位異或運(yùn)算,可以實(shí)現(xiàn)兩個(gè)值的交換,而不必使用臨時(shí)變量。例如交

換兩個(gè)整數(shù)a,b的值,可通過下列語句實(shí)現(xiàn):

a=10100001,b=00000110

a=a^b;//a=10100111

b=b^a;//b=10100001

a=a"b;//a=00000110

(3)異或運(yùn)算符的特點(diǎn)是:數(shù)a兩次異或同一個(gè)數(shù)b(a=個(gè)b'b)仍然為原值a.

三,Java中除了二進(jìn)制的表示方法:

由于數(shù)據(jù)在計(jì)算機(jī)中的表示,最終以二進(jìn)制的形式存在,所以有時(shí)候使用二進(jìn)制,

可以更直觀地解決問題。

但,二進(jìn)制數(shù)太長(zhǎng)了。比如int類型占用4個(gè)字節(jié),32位。比如100,用

int類型的二進(jìn)制數(shù)表達(dá)將是:

000000000000000001100100

面對(duì)這么長(zhǎng)的數(shù)進(jìn)行思考或操作,沒有人會(huì)喜歡。因此,C,C++,以及java

中沒有提供在代碼直接寫二進(jìn)制數(shù)的方法。

八進(jìn)制數(shù)的表達(dá)方法

如何表達(dá)一個(gè)八進(jìn)制數(shù)呢?如果這個(gè)數(shù)是876,我們可以斷定它不是八進(jìn)制

數(shù),因?yàn)榘诉M(jìn)制數(shù)中不可能出7以上的阿拉伯?dāng)?shù)字。但如果這個(gè)數(shù)是123、是567,

或12345670,那么它是八進(jìn)制數(shù)還是八進(jìn)制數(shù),都有可能。

所以規(guī)定,一個(gè)數(shù)如果要指明它采用八進(jìn)制,必須在它前面加上一個(gè)0,如:123

是十進(jìn)制,但0123則表示采用八進(jìn)制。這就是八進(jìn)制數(shù)的表達(dá)方法。

現(xiàn)在,對(duì)于同樣一個(gè)數(shù),比如是100,我們?cè)诖a中可以用平常的10進(jìn)制表達(dá),

例如在變量初始化時(shí):

inta=100;

我們也可以這樣寫:

inta=0144;〃0144是八進(jìn)制的100;一個(gè)10進(jìn)制數(shù)如何

轉(zhuǎn)成8進(jìn)制。

千萬記住,用八進(jìn)制表達(dá)時(shí),你不能少了最前的那個(gè)0。否則計(jì)算機(jī)會(huì)通通當(dāng)成

10進(jìn)制。不過,有一個(gè)地方使用八進(jìn)制數(shù)時(shí),卻不能使用加0,那就是我們前面

學(xué)的用于表達(dá)字符的“轉(zhuǎn)義符”表達(dá)法。

十六進(jìn)制數(shù)的表達(dá)方法

如果不使用特殊的書寫形式,16進(jìn)制數(shù)也會(huì)和10進(jìn)制相混。隨便一個(gè)數(shù):9876,

就看不出它是16進(jìn)制或10進(jìn)制。

16進(jìn)制數(shù)必須以O(shè)x開頭。比如0x1表示一個(gè)16進(jìn)制數(shù)。而1則表示

一個(gè)十進(jìn)制。另外如:Oxff,OxFF,0X102A,等等。其中的x也也不區(qū)分大小寫.(注

意:Ox中的0是數(shù)字0,而不是字母0)

以下是一些用法示例:

inta=OxlOOF;

intb=0x70+a;

最后一點(diǎn)很重要,10進(jìn)制數(shù)有正負(fù)之分,比如12表示正12,而T2表示負(fù)12,;

但8進(jìn)制和16進(jìn)制只能用達(dá)無符號(hào)的正整數(shù),如果你在代碼中里:-078,或者

寫:-0xF2,編譯器并不把它當(dāng)成一個(gè)負(fù)數(shù)。

/*位運(yùn)算

*java使用補(bǔ)碼來表示2進(jìn)制數(shù),最高位為符號(hào)位,正數(shù)為0,負(fù)數(shù)為1,補(bǔ)碼規(guī)定:

*整數(shù),最高位是0,其余是本身,如+42的補(bǔ)碼為00101010

*負(fù)數(shù),最高位是1,將其余的決定值按位取反,最后+1,即為負(fù)數(shù)的補(bǔ)碼;

*如-42的補(bǔ)碼為11010110(00101010按位取反11010101

+1=11010110)

si*

,,、rj**Jw,,、

*邏輯運(yùn)算*

?£?*£*?£??X**1*

*i**7**7、*i?,]、,[、*7**,?

a&b與門[真真為真,真假為假]

00000000000000000000000000000001

00000000000000000000000000000010

00000000000000000000000000000000

System,out.printin(1&2);

結(jié)果為0

a|b或門[假假為假,其余全真]

00000000000000000000000000000001

00000000000000000000000000000010

00000000000000000000000000000011

System.out.println(12);

結(jié)果為3

~a非門[真則假,假則真]

00000000000000000000000000000001

11111111111111111111111111111110

System.out.printIn("1);

結(jié)果為:—2

a'b異或門:[相同為假,不同為真]

00000000000000000000000000000001

00000000000000000000000000000010

00000000000000000000000000000011

System.out.printin(/2);

結(jié)果為3

*T*

*移位運(yùn)算*

*1**1**1*

a>>b有符號(hào)右移位;將a右移b位;若正數(shù),高位補(bǔ)0,負(fù)數(shù),高位補(bǔ)1

00000000000000000000000000000011

?1

00000000000000000000000000000001

System.out.printin(3>>1);

結(jié)果為1,結(jié)果與3/2的1次基相同

a?b有符號(hào)左移位;將a左移b位,若正數(shù),高位補(bǔ)0,負(fù)數(shù),高位補(bǔ)1

00000000000000000000000000000011

?2

00000000000000000000000000001100

System.out.printin(3?2);

結(jié)果為12,與3*2的2次第相同

a?>b無符號(hào)右移位;將a左移b位,不論正負(fù),高位均補(bǔ)0

00000000000000000000000000000011

?1

00000000000000000000000000000001

System.out.printIn(3?>1);

結(jié)果為1,與3/2的1次幕相同

*/

System.out.printin(3?>1);

System.out.printin(i;

Java定義的位運(yùn)算(bitwiseoperators)直接對(duì)整數(shù)類型的位進(jìn)行操作,這

些整數(shù)類型包括long,int,short,char,andbyte。

運(yùn)算符結(jié)果

~按位非(NOT)(一元運(yùn)算)

&按位與(AND)

I按位或(OR)

“按位異或(XOR)

〉〉右移

?>右移,左邊空出的位以。填充

運(yùn)算符結(jié)果

?左移

&-按位與賦值

1=按位或賦值

J按位異或賦值

?=右移賦值

?>=右移賦值,左邊空出的位以0填充

?=左移賦值

既然位運(yùn)算符在整數(shù)范圍內(nèi)對(duì)位操作,因此理解這樣的操作會(huì)對(duì)一個(gè)值產(chǎn)生什么

效果是重要的。具體坦說,知道Java是如何存儲(chǔ)整數(shù)值并且如何表示負(fù)數(shù)的是

有用的。因此,在繼續(xù)討論之前,讓我們簡(jiǎn)短概述一下這兩個(gè)話題。

所有的整數(shù)類型以二進(jìn)制數(shù)字位的變化及其寬度來表示。例如,byte型值42

的二進(jìn)制代碼是00101010,其中每個(gè)位置在此代表2的次方,在最右邊的位以

20開始。向左下一個(gè)位置將是21,或2,依次向左是22,或4,然后是8,16,

32等等,依此類推。因此42在其位置1,3,5的值為1(從右邊以0開始數(shù));

這樣42是21十23+25的和,也即是2+8+32。

所有的整數(shù)類型(除了char類型之外)都是有符號(hào)的整數(shù)。這意味著他們既

能表示正數(shù),又能表示負(fù)數(shù)。Java使用大家知道的2的補(bǔ)碼(two,s

complement)這種編碼來表示負(fù)數(shù),也就是通過將與其對(duì)應(yīng)的正數(shù)的二進(jìn)制代

碼取反(即將1變成0,將0變成1),然后對(duì)其結(jié)果加1。例如,-42就是通過

將42的二進(jìn)制代碼的各個(gè)位取反,即對(duì)00101010取反得到11010101,然后

再加1,得到11010110,BP-42。要對(duì)一個(gè)負(fù)數(shù)解碼,首先對(duì)其所有的位取反,

然后加1。例如-42,或11010110取反后為00101001,或41,然后加1,這樣

就得到了42。

如果考慮到零的交叉(zerocrossing)問題,你就容易理解Java(以及其他

絕大多數(shù)語言)這樣用2的補(bǔ)碼的原因。假定byte類型的值冬用00000000代

表。它的補(bǔ)碼是僅僅將它的每一位取反,即生成11111111,它代表負(fù)零。但問

題是負(fù)零在整數(shù)數(shù)學(xué)中是無效的。為了解決負(fù)零的問題,在使用2的補(bǔ)碼代表負(fù)

數(shù)的值時(shí),對(duì)其值加lo即負(fù)零11111111加1后為100000000o但這樣使1位

太靠左而不適合返回到byte類型的值,因此人們規(guī)定,-0和0的表示方法一樣,

7的解碼為11111111。盡管我們?cè)谶@個(gè)例子使用了byte類型的值,但同樣的

基本的原則也適用于所有Java的整數(shù)類型。

因?yàn)镴ava使用2的補(bǔ)碼來存儲(chǔ)負(fù)數(shù),并且因?yàn)镴ava中的所有整數(shù)都是有符號(hào)

的,這樣應(yīng)用位運(yùn)算符可以容易地達(dá)到意想不到的結(jié)果。例如,不管你如何打算,

Java用高位來代表負(fù)數(shù)。為避免這個(gè)討厭的意外,請(qǐng)記住不管高位的順序如何,

它決定一個(gè)整數(shù)的符號(hào)。

4.2.1位邏輯運(yùn)算符

位邏輯運(yùn)算符有“與"(AND)、“或"(0R)、“異或(XOR)”、“非(NOT)”,

分別用“&”、「”、?”、…表示,4-3表顯示了每個(gè)位邏輯運(yùn)算的結(jié)果。

在繼續(xù)討論之前,請(qǐng)記住位運(yùn)算符應(yīng)用于每個(gè)運(yùn)算數(shù)內(nèi)的每個(gè)單獨(dú)的位。

表4-3位邏輯運(yùn)算符的結(jié)果

A0101B0011A|B0111A&B0001A"B0110"A101

0

按位非(NOT)

按位非也叫做補(bǔ),一元運(yùn)算符NOT是對(duì)其運(yùn)算數(shù)的每一位取反。例如,數(shù)

字42,它的二進(jìn)制代碼為:

00101010

經(jīng)過按位非運(yùn)算成為

11010101

按位與(AND)

按位與運(yùn)算符“&”,如果兩個(gè)運(yùn)算數(shù)都是1,則結(jié)果為1。其他情況下,結(jié)果均

為零??聪旅娴睦樱?/p>

0010101042&0000111115

0000101010

按位或(OR)

按位或運(yùn)算符“I”,任何一個(gè)運(yùn)算數(shù)為1,則結(jié)果為1。如下面的例子所示:

0010101042|0000111115

0010111147

按位異或(XOR)

按位異或運(yùn)算符“一",只有在兩個(gè)比較的位不同時(shí)其結(jié)果是k否則,結(jié)果是

零。下面的例子顯示了“一’運(yùn)算符的效果。這個(gè)例子也表明了XOR運(yùn)算符的一

個(gè)有用的屬性。注意第二個(gè)運(yùn)算數(shù)有數(shù)字1的位,42對(duì)應(yīng)二進(jìn)制代碼的對(duì)應(yīng)位

是如何被轉(zhuǎn)換的。第二個(gè)運(yùn)算數(shù)有數(shù)字0的位,第一個(gè)運(yùn)算數(shù)對(duì)應(yīng)位的數(shù)字不

變。當(dāng)對(duì)某些類型進(jìn)行位運(yùn)算時(shí),你將會(huì)看到這個(gè)屬性的用處。

0010101042,0000111115

0010010137

位邏輯運(yùn)算符的應(yīng)用

下面的例子說明了位邏輯運(yùn)算符:

//Demonstratethebitwiselogicaloperators.

classBitLogic{

publicstaticvoidnain(Stringargs[]){

Stringbinary[]={〃0000〃,〃0001〃,〃0010〃,〃0100〃,〃0110〃,

〃oiu〃,〃iooo〃,〃iou〃,〃noo〃,

};

inta=3;//0+2+1or0011inbinary

intb=6;//4+2+0or0110inbinary

intc=a|b;

intd=a&b;

inte=ab;

intf=(~a&b)|ia&~b);

intg=~a&OxOf;

System.out.printIn(*a="+binary[a]);

System.out.printinC'b=〃+binary);

System.out.printIna|b=〃+binary[c]);

System,out.printinCa&b=〃+binary[d]);

System.out.printinCab=〃+binary[e]);

System.out.printin("~a&b|a&~b=〃+binary[f]);

System.out.printin(*=〃+binary[g]);

)

)

在本例中,變量a與b對(duì)應(yīng)位的組合代表了二進(jìn)制數(shù)所有的4種組合模式:0-0,

0-1,1-0,和1-1。運(yùn)算符和運(yùn)算符分別對(duì)變量a與b各個(gè)對(duì)應(yīng)位

的運(yùn)算得到了變量c和變量d的值。對(duì)變量e和f的賦值說明了運(yùn)算符的

功能。字符串?dāng)?shù)組binary代表了0到15對(duì)應(yīng)的二進(jìn)制的值。在本例中,數(shù)組

各元素的排列順序顯示了變量對(duì)應(yīng)值的二進(jìn)制代碼。數(shù)組之所以這樣構(gòu)造是因?yàn)?/p>

變量的值n對(duì)應(yīng)的二進(jìn)制代碼可以被正確的存儲(chǔ)在數(shù)組對(duì)應(yīng)元素binary[n]

中。例如變量a的值為3,則它的二進(jìn)制代碼對(duì)應(yīng)地存儲(chǔ)在數(shù)組元素binab[3]

中。%的值與數(shù)字OxOf(對(duì)應(yīng)二進(jìn)制為00001111)進(jìn)行按位與運(yùn)算的目的

是減?。サ闹?,保證變量g的結(jié)果小于16。因此該程序的運(yùn)行結(jié)果可以用數(shù)組

binary對(duì)應(yīng)的元素來表示。該程序的輸出如下:

a=0011b=0110a|b=0111a&b=0010a^b=0101?a&b|a&~b=0101

=1100

4.2.2左移運(yùn)算符

左移運(yùn)算符《使指定值的所有位都左移規(guī)定的次數(shù)。它的通用格式如下所示:

value<<num

這里,num指定要移位值value移動(dòng)的位數(shù)。也就是,左移運(yùn)算符<〈使指定值

的所有位都左移num位。每左移一個(gè)位,高階位都被移出(并且丟棄),并用0

填充右邊。這意味著當(dāng)左移的運(yùn)算數(shù)是int類型時(shí),每移動(dòng)1位它的第3:位

就要被移出并且丟棄;當(dāng)左移的運(yùn)算數(shù)是long類型時(shí),每移動(dòng)1位它的第63

位就要被移出并且丟棄。

在對(duì)byte和short類型的值進(jìn)行移位運(yùn)算時(shí),你必須小心。因?yàn)槟阒繨ava在

對(duì)表達(dá)式求值時(shí),將自動(dòng)把這些類型擴(kuò)大為int型,而且,表達(dá)式的值也是int

型。對(duì)byte和short類型的值進(jìn)行移位運(yùn)算的結(jié)果是int型,而且如果左移不

超過31位,原來對(duì)應(yīng)各位的值也不會(huì)丟棄。但是,如果你對(duì)一個(gè)負(fù)的byle或

者short類型的值進(jìn)行移位運(yùn)算,它被擴(kuò)大為int型后,它的符號(hào)也被擴(kuò)展。

這樣,整數(shù)值結(jié)果的高位就會(huì)被1填充。因此,為了得到正確的結(jié)果,你就要舍

棄得到結(jié)果的高位。這樣做的最簡(jiǎn)單辦法是將結(jié)果轉(zhuǎn)換為byte型。下面的程序

說明了這一點(diǎn):

//Leftshiftingabytevalue.

classByteShift{

publicstaticvoidnain(Stringargs[]){

bytea=64,b;

inti;

i=a?2;

b=(byte)(a<<2):

System.out.printin(^Originalvalueofa:〃+a);

System.out.printIn(^iandb:〃+i+〃〃+b);

)

)

該程序產(chǎn)生的輸出下所示:

Originalvalueofa:64

iandb:2560

因變量a在賦值表達(dá)式中,故被擴(kuò)大為int型,64(01000000)被左移兩次

生成值256(100000000)被賦給變量i。然而,經(jīng)過左移后,變量b中惟一

的1被移出,低位全部成了0,因此b的值也變成了0。

既然每次左移都可以使原來的操作數(shù)翻倍,程序員們經(jīng)常使用這個(gè)辦法來進(jìn)行快

速的2的乘法。但是你要小心,如果你將1移進(jìn)高階位(31或63位),那么該

值將變?yōu)樨?fù)值。下面的程序說明了這一點(diǎn):

//Leftshiftingasaquickwaytomultiplyby2.

classMuItByTwo{

publicstaticvoidnain(Stringargs[]){

inti;

intnum=OxFFFFFFE:

for(i=0;i<4;i++)(

num=num<<1;

System.out.printin(num);

)

}

這num指定要移位值value移動(dòng)的位數(shù)。也就是,左移運(yùn)算符《使指定值

的所有位都左移num位。每左移一個(gè)位,高階位都被移出(并且丟棄),并用0

填充右邊。這意味著當(dāng)左移的運(yùn)算數(shù)是int類型時(shí),每移動(dòng)1位它的第3:位

就要被移出并且丟棄;當(dāng)左移的運(yùn)算數(shù)是long類型時(shí),每移動(dòng)1位它的第63

位就要被移出并且丟棄。

在對(duì)byte和short類型的值進(jìn)行移位運(yùn)算時(shí),你必須小心。因?yàn)槟阒繨ava在

對(duì)表達(dá)式求值時(shí),將自動(dòng)把這些類型擴(kuò)大為int型,而且,表達(dá)式的值也是int

型。對(duì)byte和short類型的值進(jìn)行移位運(yùn)算的結(jié)果是ini型,而且如果左移不

超過31位,原來對(duì)應(yīng)各位的值也不會(huì)丟棄。但是,如果你對(duì)一個(gè)負(fù)的byte或

者short類型的值進(jìn)行移位運(yùn)算,它被擴(kuò)大為int型后,它的符號(hào)也被擴(kuò)展。

這樣,整數(shù)值結(jié)果的高位就會(huì)被1填充。因此,為了得到正確的結(jié)果,你就要舍

棄得到結(jié)果的高位。這樣做的最簡(jiǎn)單辦法是將結(jié)果轉(zhuǎn)換為byte型。下面的程序

說明了這一點(diǎn):

//Leftshiftingabytevalue.

classByteShift{

publicstaticvoidnain(Stringargs[]){

bytea=64,b;

inti;

i=a?2;

b=(byte)(a<<2);

System,out.printin(^Originalvalueofa:〃+a);

System.out.printinandb:"+i+"〃+b);

)

)

該程序產(chǎn)生的輸出下所示:

Originalvalueofa:64

iandb:2560

因變量a在賦值表達(dá)式中,故被擴(kuò)大為int型,64(01000000)被左移兩次

生成值256(100000000)被賦給變量i。然而,經(jīng)過左移后,變量b中惟一

的1被移出,低位全部成了0,因此b的值也變成了0。

既然每次左移都可以使原來的操作數(shù)翻倍,程序員們經(jīng)常使用這個(gè)辦法來進(jìn)行快

速的2的乘法。但是你要小心,如果你將1移進(jìn)高階位(31或63位),那么該

值將變?yōu)樨?fù)值。下面的程序說明了這一點(diǎn):

//Leftshiftingasaquickwaytomultiplyby2.

classMuItByTwo{

publicstaticvoidnain(Stringargs[]){

inti;

intnum=OxFFFFFFE:

for(i=0;i<4;i++)(

num=num<<1;

System.out.printin(num);

)

)

)

該程序的輸出如下所示:

536870908

1073741816

2147483632

-32

初值經(jīng)過仔細(xì)選擇,以便在左移4位后,它會(huì)產(chǎn)生-32。正如你看到的,當(dāng)1

被移進(jìn)31位時(shí),數(shù)字被解釋為負(fù)值。

4.2.3右移運(yùn)算符

右移運(yùn)算符》使指定值的所有位都右移規(guī)定的次數(shù)。它的通用格式如下所示:

value>>num

這里,num指定要移位值value移動(dòng)的位數(shù)。也就是,右移運(yùn)算符*使指定值

的所有位都右移num位。下面的程序片段將值32右移2次,將結(jié)果8賦給變量

a:

inta=32;

a=a>>2;//anowcontains8

當(dāng)值中的某些位被“移出”時(shí),這些位的值將丟棄。例如,下面的程序片段將

35右移2次,它的2個(gè)低位被移出丟棄,也將結(jié)果8賦給變量a:

inta=35;

a=a?2;//astillcontains8

用二進(jìn)制表示該過程兀以更清楚地看到程序的運(yùn)行過程:

0010001135

?2

000010008

將值每右移一次,就相當(dāng)于將該值除以2并且舍棄了余數(shù)。你可以利用這個(gè)特點(diǎn)

將一個(gè)整數(shù)進(jìn)行快速的2的除法。當(dāng)然,你一定要確保你不會(huì)將該數(shù)原有的任何

一位移出。

右移時(shí),被移走的最高位(最左邊的位)由原來最高位的數(shù)字補(bǔ)充。例如,如

果要移走的值為負(fù)數(shù),每一次右移都在左邊補(bǔ)1,如果要移走的值為正數(shù),每一

次右移都在左邊補(bǔ)0,這叫做符號(hào)位擴(kuò)展(保留符號(hào)位)(signext6nsion),

在進(jìn)行右移操作時(shí)用來保持負(fù)數(shù)的符號(hào)。例如,-8>>1是-4,用二進(jìn)制表示

如下:

11111000-8?111111100-4

一個(gè)要注意的有趣問題是,由于符號(hào)位擴(kuò)展(保留符號(hào)位)每次都會(huì)在高位補(bǔ)1,

因此T右移的結(jié)果總是-1。有時(shí)你不希望在右移時(shí)保留符號(hào)。例如,下面的例

子將一個(gè)byte型的值轉(zhuǎn)換為用十六

進(jìn)制表示。注意右移后的值與OxOf進(jìn)行按位與運(yùn)算,這樣可以舍棄任何的符號(hào)

位擴(kuò)展,以便得到的值可以作為定義數(shù)組的下標(biāo),從而得到對(duì)應(yīng)數(shù)組元素代表的

十六進(jìn)制字符。

//Maskingsignextension.

classHexByte{

staticpublicvoidnain(Stringargs[]){

charhex[]={

'8','9','a','b','c','d','e','f''

};

byteb=(byte)Oxfl;

System,out.printin(^b=0x〃+hex[(b>>4)&OxOf]+hex[b&OxOf]);J)

該程序的輸出如下:

b=Oxfl

4.2.4無符號(hào)右移

正如上面剛剛看到的,每一次右移,>>運(yùn)算符總是自動(dòng)地用它的先前最高位的

內(nèi)容補(bǔ)它的最高位。這樣做保留了原值的符號(hào)。但有時(shí)這并不是我們想要的。

例如,如果你進(jìn)行移位操作的運(yùn)算數(shù)不是數(shù)字值,你就不希望進(jìn)行符號(hào)位擴(kuò)展(保

留符號(hào)位)。當(dāng)你處理像素值或圖形時(shí),這種情況是相當(dāng)普遍的。在這種情況下,

不管運(yùn)算數(shù)的初值是什么,你希望移位后總是在高位(最左邊)補(bǔ)0。這就是人

們所說的無符號(hào)移動(dòng)(unsignedshift)<>這時(shí)你可以使用Java的無符號(hào)右

移運(yùn)算符>>>,它總是在左邊補(bǔ)0。

下面的程序段說明了無符號(hào)右移運(yùn)算符>〉>o在本例中,變量a被賦值為T,用

二進(jìn)制表示就是32位全是1。這個(gè)值然后被無符號(hào)右移24位,當(dāng)然它忽略了符

號(hào)位擴(kuò)展,在它的左邊總是補(bǔ)0。這樣得到的值255被賦給變量a。

inta=-1;a=a>?24;

下面用二進(jìn)制形式進(jìn)一步說明該操作:

11111111111111111111111111111111int型T的二進(jìn)制代碼>>>24無符號(hào)

右移24位00000000000000000000000011111111int型255的二進(jìn)制代碼

由于無符號(hào)右移運(yùn)算符>>>只是對(duì)32位和64位的值有意義,所以它并不像你

想象的那樣有用。因?yàn)槟阋涀?,在表達(dá)式中過小的值總是被自動(dòng)擴(kuò)大為int

型。這意味著符號(hào)位擴(kuò)展和移動(dòng)總是發(fā)生在32位而不是8位或16位。這樣,對(duì)

第7位以0開始的byte型的值進(jìn)行無符號(hào)移動(dòng)是不可能的,因?yàn)樵趯?shí)際移動(dòng)運(yùn)

算時(shí),是對(duì)擴(kuò)大后的32位值進(jìn)行操作。下面的例子說明了這一點(diǎn):

//Unsignedshiftingabytevalue.

classByteUShift{

staticpublicvoidnain(Stringargs[]){

進(jìn)制表示。注意右移后的值與OxOf進(jìn)行按位與運(yùn)算,這樣可以舍棄任何的符號(hào)

位擴(kuò)展,以便得到的值可以作為定義數(shù)組的下標(biāo),從而得到對(duì)應(yīng)數(shù)組元素代表的

十六進(jìn)制字符。

//Maskingsignextension.

classHexByte{

staticpublicvoidnain(Stringargs[]){

charhex[]=(

'8','9','a','b','c','d','e','f''

};

byteb=(byte)Oxfl;

System,out.printin(*b=0x〃+hex[(b?4)&OxOf]+hex[b&OxOf]);}}

該程序的輸出如下:

b=Oxfl

4.2.4無符號(hào)右移

正如上面剛剛看到的,每一次右移,*運(yùn)算符總是自動(dòng)地用它的先前最高位的

內(nèi)容補(bǔ)它的最高位。這樣做保留了原值的符號(hào)。但有時(shí)這并不是我們想要的。

例如,如果你進(jìn)行移位噪作的運(yùn)算數(shù)不是數(shù)字值,你就不希望進(jìn)行符號(hào)位擴(kuò)展(保

留符號(hào)位)。當(dāng)你處理像素值或圖形時(shí),這種情況是相當(dāng)普遍的。在這種情況下,

不管運(yùn)算數(shù)的初值是什么,你希望移位后總是在高位(最左邊)補(bǔ)0。這就是人

們所說的無符號(hào)移動(dòng)(unsignedshift)。這時(shí)你可以使用Java的無符號(hào)右

移運(yùn)算符>>>,它總是在左邊補(bǔ)0。

下面的程序段說明了無符號(hào)右移運(yùn)算符>〉>o在本例中,變量a被賦值為-1,用

二進(jìn)制表示就是32位全是1。這個(gè)值然后被無符號(hào)右移24位,當(dāng)然它忽略了符

號(hào)位擴(kuò)展,在它的左邊總是補(bǔ)0。這樣得到的值255被賦給變量a。

inta=-1;a=a?>24;

下面用二進(jìn)制形式進(jìn)一步說明該操作:

11111111111111111111111111111111int型-1的二進(jìn)制代碼>>>24無符號(hào)

右移24位00000000000000000000000011111111int型255的二進(jìn)制代碼

由于無符號(hào)右移運(yùn)算符只是對(duì)32位和64位的值有意義,所以它并不像你

想象的那樣有用。因?yàn)槟阋涀。诒磉_(dá)式中過小的值總是被自動(dòng)擴(kuò)大為int

型。這意味著符號(hào)位擴(kuò)展和移動(dòng)總是發(fā)生在32位而不是8位或16位。這樣,對(duì)

第7位以0開始的byte型的值進(jìn)行無符號(hào)移動(dòng)是不可能的,因?yàn)樵趯?shí)際移動(dòng)運(yùn)

算時(shí),是對(duì)擴(kuò)大后的32位值進(jìn)行操作。下面的例子說明了這一點(diǎn):

//Unsignedshiftingabytevalue.

classByteUShift{

staticpublicvoidnain(Stringargs[]){

intb=2;

intc=3;

a|=4;

b?=1;

c?=1;

a-=c;

System.out.printin(*a=〃+a);

System.out.printin(*b=〃+b);

System.out.printin(*c="+c);

)

)

該程序的輸出如下所示:

a=3

b=1

C=6附錄資料:

java處理高并發(fā)高負(fù)載類網(wǎng)站的優(yōu)化方法

java處理高并發(fā)高負(fù)載類網(wǎng)站中數(shù)據(jù)庫(kù)的設(shè)計(jì)方法(java教程Java處理大量數(shù)

據(jù),java高負(fù)載數(shù)據(jù))

-:高并發(fā)高負(fù)載類網(wǎng)站關(guān)注點(diǎn)之?dāng)?shù)據(jù)庫(kù)

沒錯(cuò),首先是數(shù)據(jù)庫(kù),這是大多數(shù)應(yīng)用所面臨的首個(gè)SPOF。尤其是Web2.0的應(yīng)

用,數(shù)據(jù)庫(kù)的響應(yīng)是首先要解決的。一般來說MySQL是最常用的,可能最初是

一個(gè)mysql主機(jī),當(dāng)數(shù)據(jù)增加到100萬以上,那么,MySQL的效能急劇下降。

常用的優(yōu)化措施是M-S(主-從)方式進(jìn)行同步復(fù)制,將查詢和操作和分別在不

同的服務(wù)器上進(jìn)行操作。我推薦的是M-M-Slaves方式,2個(gè)主Mysql,多個(gè)

Slaves,需要注意的是,雖然有2個(gè)Master,但是同時(shí)只有1個(gè)是Active,我

們可以在一定時(shí)候切換。之所以用2個(gè)M,是保證M不會(huì)又成為系統(tǒng)的SPOF。

Slaves可以進(jìn)一步負(fù)載均衡,可以結(jié)合LVS,從而將select操作適當(dāng)?shù)钠胶獾讲?/p>

同的slaves上。以上架構(gòu)可以抗衡到一定量的負(fù)載,但是隨著用戶進(jìn)一步增加,

你的用戶表數(shù)據(jù)超過1千萬這時(shí)那個(gè)M變成了SPOF。你不能任意擴(kuò)充Slaves,

否則復(fù)制同步的開銷將直線上升,怎么辦?我的方法是表分區(qū),從業(yè)務(wù)層面上進(jìn)

行分區(qū)。最簡(jiǎn)單的,以用戶數(shù)據(jù)為例。根據(jù)一定的切分方式,比如id,切分到

不同的數(shù)據(jù)庫(kù)集群去。

全局?jǐn)?shù)據(jù)庫(kù)用于meta數(shù)據(jù)的查詢。缺點(diǎn)是每次查詢,會(huì)增加一次,比如你要查

一個(gè)用戶nightsailer,你首先要到全局?jǐn)?shù)據(jù)庫(kù)群找到nightsailer對(duì)應(yīng)的cluster

id,然后再到指定的cluster找至I」nightsailer的實(shí)際數(shù)據(jù)。每個(gè)cluster可以用

m-m方式,或者m-m-slaves方式。這是一個(gè)可以擴(kuò)展的結(jié)構(gòu),隨著負(fù)載的增

加,你可以簡(jiǎn)單的增加新的mysqlcluster進(jìn)去。

需要注意的是:1、禁用全部auto_increment的字段2、id需要采用通用的算

法集中分配3、要具有比較好的方法來監(jiān)控mysql主機(jī)的負(fù)載和服務(wù)的運(yùn)行狀

態(tài)。如果你有30臺(tái)以上的mysql數(shù)據(jù)庫(kù)在跑就明白我的意思了。4、不要使用

持久性鏈接(不要用pconnect)相反,使用sqlrelay這種第三方的數(shù)據(jù)庫(kù)鏈接

池,或者干脆自己做,因?yàn)閜hp4中mysql的鏈接池經(jīng)常出問題。二:高并發(fā)

高負(fù)載網(wǎng)站的系統(tǒng)架構(gòu)之HTML靜態(tài)化

其實(shí)大家都知道,效率最高、消耗最小的就是純靜態(tài)化,所以我們盡可能使我們

的網(wǎng)站上的頁面采用靜態(tài)頁面來實(shí)現(xiàn),這個(gè)最簡(jiǎn)單的方法其實(shí)也是最有效的方

法。但是對(duì)于大量?jī)?nèi)容并且頻繁更新的網(wǎng)站,我們無法全部手動(dòng)去挨個(gè)實(shí)現(xiàn),于

是出現(xiàn)了我們常見的信息發(fā)布系統(tǒng)CMS,像我們常訪問的各個(gè)門戶站點(diǎn)的新聞

頻道,甚至他們的其他頻道,都是通過信息發(fā)布系統(tǒng)來管理和實(shí)現(xiàn)的,信息發(fā)布

系統(tǒng)可以實(shí)現(xiàn)最簡(jiǎn)單的信息錄入自動(dòng)生成靜態(tài)頁面,還能具備頻道管理、權(quán)限管

理、自動(dòng)抓取等功能,對(duì)于一個(gè)大型網(wǎng)站來說,擁有一套高效、可管理的CMS

是必不可少的。除了門戶和信息發(fā)布類型的網(wǎng)站,對(duì)于交互性要求很高的社

區(qū)類型網(wǎng)站來說,盡可能的靜態(tài)化也是提高性能的必要手段,將社區(qū)內(nèi)的帖子、

文章進(jìn)行實(shí)時(shí)的靜態(tài)化,有更新的時(shí)候再重新靜態(tài)化也是大量使用的策略,像

Mop的大雜燒就是使用了這樣的策略,網(wǎng)易社區(qū)等也是如此。同時(shí),html

靜態(tài)化也是某些緩存策略使用的手段,對(duì)于系統(tǒng)中頻繁使用數(shù)據(jù)庫(kù)查詢但是內(nèi)容

更新很小的應(yīng)用,可以考慮使用html靜態(tài)化來實(shí)現(xiàn),比如論壇中論壇的公用

設(shè)置信息,這些信息目前的主流論壇都可以進(jìn)行后臺(tái)管理并且存儲(chǔ)再數(shù)據(jù)庫(kù)中,

這些信息其實(shí)大量被前臺(tái)程序調(diào)用,但是更新頻率很小,可以考慮將這部分內(nèi)

容進(jìn)行后臺(tái)更新的時(shí)候進(jìn)行靜態(tài)化,這樣避免了大量的數(shù)據(jù)庫(kù)訪問請(qǐng)求高并發(fā)。

網(wǎng)站HTML靜態(tài)化解戾方案當(dāng)一個(gè)Servlet資源清求到達(dá)WEB服務(wù)器之后我們

會(huì)填充指定的JSP頁面來響應(yīng)請(qǐng)求:

HTTP請(qǐng)求Web服務(wù)器-Servlet一業(yè)務(wù)邏輯處理--訪問數(shù)據(jù)--填充JSP--響

應(yīng)請(qǐng)求

HTML靜態(tài)化之后:

HTTP請(qǐng)求???Web月艮務(wù)器Servlet--HTML--響應(yīng)請(qǐng)求

靜態(tài)訪求如下

Servlet:

publicvoiddoGet(HttpServletRequestrequest,HttpServletResponse

response)throwsServletException,lOException

{if(request.getParameter("chapterIdn)!=null){String

chapterFileName=

nbookChapterRead_'+request.getRarameter("chapterId")+n.html";

StringchapterFilePath=getServletContext(),getRealPath(7")+

chapterFileName;FilechapterFile=new

File(chapterFilePath);if(chapterFile.exists()){response.sendRedirect

(chapterFileName);return;}//如果有這個(gè)文件就告訴瀏覽器轉(zhuǎn)

向INovelChapterBiznovelChapterBiz=new

NovelChapterBizImplQ;Novelchapternovelchapter=

novelChapterBiz.searchNovelChapterById(Integer.parseInt(request.getP

arameter("chapterld")));//章節(jié)信息intlastPageld=

novelChapterBiz.searchLastCHapterId(novelChapter.getNovelId().getId(),

novelChapter.getldO);intnextPageld=

novelChapterBiz.searchNextChapterId(novelChapter.getNovelId().getId()/

novelChapter.getldO);request.setAttribute(nnovelchapter",

novelchapter);request.setAttribute("lastPageId",

lastPageld);request.setAttribute("nextPageId",

nextPageld);new

CreateStaticHTMLPage().createStaticHTMLPage(request,response,

getServletContext(),chapterFileName,chapterFilePath,

VbookRead.jsp");}}生成HTML靜態(tài)頁面的類:

packagecomjb.y2t034.thefifth.web.servlet;import

java.io.ByteArrayOutputStream;import

java.io.FileOutputStream;importjava.io.IOException;import

java.io.OutputStreamWriter;importjava.io.PrintWriter;import

javax.servlet.RequestDispatcher;import

javax.servlet.ServletContext;import

javax.servlet.ServletException;import

javax.servlet.ServletOutputStream;import

javax.servlet.http.HttpServletRequest;import

javax.scrvIct.http.HttpScrvletRcsponsc;import

javax.servlet.http.HttpServletResponseWrapper;/***創(chuàng)建HTML靜態(tài)頁

面*功能:創(chuàng)建HTML靜態(tài)頁面*時(shí)間:2009年1011日*地點(diǎn):home*

@authormavk**/publicclassCreateStaticHTMLPage{/***生

成靜態(tài)HTML頁面的方法*@paramrequest請(qǐng)求對(duì)象*@param

response響應(yīng)對(duì)象*@paramservletContextServlet上下文*

@paramfileName文件名稱*@paramfileFullPath文件完整路徑*

@paramjspPath需要生成靜態(tài)文件的JSP路徑(相對(duì)即可)*@throws

lOException*?throwsServletException*/publicvoid

createStaticHTMLPage(HttpServletRequestrequest,

HttpServletResponseresponse,ServletContextservletContext,String

fileName,StringfileFullPath,StringjspPath)throwsServletException,

IOException{response.setContentType("text/html;charset=gb231

2");〃設(shè)置HTML結(jié)果流編碼(即HTML文件編碼)RequestDispatcher

rd=servletContext.getRequestDispatcher(jspPath);//得至ljJSP資

源finalByteArrayOutputStreambyteArrayOutputStream=new

ByteArrayOutputStream();//用于從ServletOutputStream中接收資

源finalServletOutputStreamservletOuputStream=new

ServletOutputStream(){//用于從HttpServletResponse中接收資

源publicvoidwrite(byte[]b,intoffjnt

len){byteArrayOutputStream.write(b,off,

len);}publicvoidwrite(int

b){byteArrayOutputStream.write(b);));

inalPrintWriterprintwriternewPrintWriter(new

OutputStreamWriter(byteArrayOutputStream));〃把轉(zhuǎn)換字節(jié)流轉(zhuǎn)換成字符

流HttpServletResponsehttpServletResponse=new

HttpServletResponseWrapper(response){〃用于從response獲取結(jié)果流資

源(重寫了兩個(gè)方法)publicServletOutputStream

getOutputStream(){return

servletOuputStream;}publicPrintWriter

getWriter(){return

printWriter;}};rd.include(request,

httpServletResponse);〃發(fā)送結(jié)果流printWriter.flush();〃刷新緩沖

區(qū),把緩沖區(qū)的數(shù)據(jù)輸出FileOutputStreamfileOutputStream=new

FileOutputStream(fileFullPath);byteArrayOutputStream.writeTo(fil

eOutputStream);//把byteArrayOuputStream中的資源全部寫入到

fileOuputStream中fileOutputStream.close();〃關(guān)閉輸出流,并釋放

相關(guān)資源response.sendRedirect(fileName);〃發(fā)送指定文件流到客戶

端}}

三:高并發(fā)高負(fù)載類網(wǎng)站關(guān)注點(diǎn)之緩存、負(fù)載均衡、存儲(chǔ)

緩存是另一個(gè)大問題,我一般用memcached來做緩存集群,一般來說部署10

臺(tái)左右就差不多(10g內(nèi)存池)。需要注意一點(diǎn),千萬不能用使用swap,最好

關(guān)閉linux的sw叩。

負(fù)載均衡/加速可能上面說緩存的時(shí)候,有人第一想的是頁面靜態(tài)化,所謂的靜

態(tài)html,我認(rèn)為這是常識(shí),不屬于要點(diǎn)了。頁面的靜態(tài)化隨之帶來的是靜態(tài)服

務(wù)的負(fù)載均衡和加速。我認(rèn)為L(zhǎng)ighttped+Squid是最好的方式了。LVS

<>lighttped====>squid(s)====lighttpd

上面是我經(jīng)常用的。注意,我沒有用apache,除非特定的需求,否則我不部署

叩ache,因?yàn)槲乙话阌胮hp-fastcgi酉己合lighttpd,性能比apache+modjDhp

要強(qiáng)很多。

squid的使用可以解決文件的同步等等問題,但是需要注意,你要很好的監(jiān)控緩

存的命中率,盡可能的是高的90%以上。squid和lighttped也有很多的話題要

討論,這里不贅述。

存儲(chǔ)存儲(chǔ)也是一個(gè)大問題,一種是小文件的存儲(chǔ),比如圖片這類。另一種是大

文件的存儲(chǔ),比如搜索引擎的索引,一般單文件都超過2g以上。小文件的存儲(chǔ)

最簡(jiǎn)單的方法是結(jié)合lighttpd來進(jìn)行分布?;蛘吒纱嗍褂肦edhat的GFS,優(yōu)

點(diǎn)是應(yīng)用透明,缺點(diǎn)是費(fèi)用較高。我是指你購(gòu)買盤陣的問題。我的項(xiàng)目中,存儲(chǔ)

量是2?10Tb,我采用了分布式存儲(chǔ)。這里要解決文件的復(fù)制和冗余。這樣每個(gè)

文件有不同的冗余,這方面可以參考google的gfs的論文。大文件的存儲(chǔ),可

以參考nutch的方案,現(xiàn)在已經(jīng)獨(dú)立為hadoop子項(xiàng)目。(你可以googleit)

其他:此外,passport等也是考慮的,不過都屬于比較簡(jiǎn)單的了。四:高并發(fā)

高負(fù)載網(wǎng)站的系統(tǒng)架構(gòu)之圖片服務(wù)器分離大家知道,對(duì)于Web服務(wù)器來說,

不管是Apache.IIS還是其他容器,圖片是最消耗資源的,于是我們有必要將

圖片與頁面進(jìn)行分離,這是基本上大型網(wǎng)站都會(huì)采用的策略,他們都有獨(dú)立的

圖片服務(wù)器,甚至很多臺(tái)圖片服務(wù)器。這樣的架構(gòu)可以降低提供頁面訪問請(qǐng)求的

服務(wù)器系統(tǒng)壓力,并且可以保證系統(tǒng)不會(huì)因?yàn)閳D片問題而崩潰,在應(yīng)用服務(wù)器

和圖片服務(wù)器上,可以進(jìn)行不同的配置優(yōu)化,比如apache在配置ContentType

的時(shí)候可以盡量少支持,盡可能少的LoadModule,保證更高的系統(tǒng)消耗和執(zhí)

行效率。

利用Apache實(shí)現(xiàn)圖片服務(wù)器的分離緣由:起步階段的應(yīng)用,都可能部署在一

臺(tái)服務(wù)器上(費(fèi)用上的原因)第一個(gè)優(yōu)先分離的肯定是數(shù)據(jù)庫(kù)和應(yīng)用服務(wù)器。第

二個(gè)分離的,會(huì)是什么呢?各有各的考慮,我所在的項(xiàng)目組重點(diǎn)考慮的節(jié)約帶寬,

服務(wù)器性能再好,帶寬再高,并發(fā)來了,也容易撐不住。因此,我這篇文章的重

點(diǎn)在這里。這里重點(diǎn)是介紹實(shí)踐,不一定符合所有情況,供看者參考吧,環(huán)境

介紹:WEB應(yīng)用服務(wù)器:4CPU雙核2G,內(nèi)存4G部署:Win2003/Apache

HttpServer2.1/Tomcat6數(shù)據(jù)庫(kù)服務(wù)器:4CPU雙核2G,內(nèi)存4G部署:

Win2003/MSSQL2000步驟:步驟一:增力口2臺(tái)配置為:2CPU雙核2G,內(nèi)

存2G普通服務(wù)器,做資源服務(wù)器部署:Tomcat6,跑了一個(gè)圖片上傳的簡(jiǎn)單

應(yīng)用,(記得指定web.xml的〈distributable/〉),并指定域名為

采用協(xié)議步驟二:修改

resl.***.comzres2.***.com,ajpApachehttpd.conf

配置原來應(yīng)用的文件上傳功能網(wǎng)址為:1、/fileupload.html2、

/otherupload.html在httpd.conf中增加如下配置

<VirtualHost*:80>ServerAdminwebmaster@***.comProxyPass

7fileupload.htmlbalancer://rescluster/fileuploadIbmethod=byrequests

stickysession=JSESSIONIDnofailover=Offtimeout=5

maxattempts=3ProxyPass/otherupload.html

balancer://rescluster/otherupload.htmllbmethod=byrequests

stickysession=JSESSIONIDnofailover=Offtimeout=5

maxattempts=3#<!—負(fù)載均衡一,<Proxy

balancer://rescluster/>BalancerMemberajp://resl.***.com:8009

smax=5max=500ttl=120retry=300loadfactor=100

route=tomcatlBalancerMemberajp://res2.***.com:8009smax=5

max=500ttl=120retry=300loadfactor=100

route=tomcat2</Proxy></VirtualHost>步驟三,修改業(yè)務(wù)邏輯:所

有上傳文件在數(shù)據(jù)庫(kù)中均采用全url的方式保存,例如產(chǎn)品圖片路徑存成:

http://resl.***.com/upload/20090101/productl20302005.jpg

現(xiàn)在,你可以高枕無憂了,帶寬不夠時(shí),增加個(gè)幾十臺(tái)圖片服務(wù)器,只需要稍微

修改一下叩ache的配置文件,即可。

五:高并發(fā)高負(fù)載網(wǎng)站的系統(tǒng)架構(gòu)之?dāng)?shù)據(jù)庫(kù)集群和庫(kù)表散列

大型網(wǎng)站都有復(fù)雜的應(yīng)用,這些應(yīng)用必須使用數(shù)據(jù)庫(kù),那么在面對(duì)大量訪問的時(shí)

候,數(shù)據(jù)庫(kù)的瓶頸很快就能顯現(xiàn)出來,這時(shí)一臺(tái)數(shù)據(jù)庫(kù)將很快無法滿足應(yīng)用,于

是我們需要使用數(shù)據(jù)庫(kù)集群或者庫(kù)表散列。在數(shù)據(jù)庫(kù)集群方面

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論