http://www.ibm.com/developerworks/cn/java/j-jtp06197.html 一文筆記
在java中,為了提高性能,線程一般把變量從內存中備份一個副本到寄存器。volatile 關鍵字意思是易失性,明確表示
一個變量是會被多線程訪問的,每個線程在每次讀取都要從內存讀取原始副本的值,而不是緩存在寄存器中的值。每次修改
都是把值寫回到內存中。
Java語言包含兩種內在的同步機制:同步塊(或方法)和 volatile 變量。
synchronized鎖提供了兩種主要特性:
互斥(mutual exclusion) 和
可見性(visibility)?;コ饧匆淮沃辉试S一個線程持有某個特定的鎖,因此可使用該特性實現對共享數據的協調訪問協議,這樣,一次就只有一個線程能夠使用該共享數據??梢娦员仨毚_保釋放鎖之前對共享數據做出的更改對于隨后獲得該鎖的另一個線程是可見的。 否則,線程看到的共享變量可能是修改前的值或不一致的值,引發嚴重問題。
volatile能夠實現上述可見性,因為線程每次都是讀取原始版本的值,前一個線程的修改對后續線程來說是可見的。但volatile不能確?;コ?。
volatile適用的原則:
- 對變量的寫操作不依賴于當前值。
- 該變量沒有包含在具有其他變量的不變式中。
所以volatile不能用作計數器,因為計數器的自增是一個讀-增-寫的過程,不是原子操作,在volatile不確?;コ獾那闆r下,結果不準確。
不變式的意思是一個需要不變的規律,如起始要小于等于結束。上述2點簡單來說:即變量真正獨立于其他變量和自己以前的值 , 在這些
情況下可以使用
volatile
代替
synchronized
來簡化代碼。
volatile由于不阻塞線程,在性能一般比synchronized表現更好。
適用volatile的幾個場景:
1、狀態標志 比如標示服務啟動或停止。
2、獨立觀察 定期 “發布” 觀察結果供程序內部使用,
3、
結合使用 volatile 和 synchronized 實現 “開銷較低的讀-寫鎖”
@ThreadSafe
public class CheesyCounter {
private volatile int value;
// 使用volatile實現可見性,開銷低
public int getValue() { return value; }
// 使用synchronized實現互斥
public synchronized int increment() {
return value++;
}
}
posted @
2011-04-08 16:28 liucs 閱讀(372) |
評論 (0) |
編輯 收藏
本文是閱讀《高性能網站建設指南》一書的筆記。該書作者是Yahoo!的
Steve Souders ,總結了yahoo!在web前端優化的最佳實踐。
Web前端性能黃金法則:只有10%-20%的最終用戶響應時間花在下載html文檔上。其余時間花在了下載頁面中所有的組件上。
頁面組件包括:圖片,javascript,css,flash等內容
Http請求響應
GET /home/**.js
HTTP 1.1
Host: www.taobao.com
User-Agent: Mozilla/**
Accept-Encoding:gzip,deflate ----》支持壓縮
If-Modified-since:web,22 Feb** -----》判斷是否采用瀏覽器緩存
Expires:web**** -----》明確聲明失效時間,避免If-Modified-since條件請求的至少一次與服務器的交互
Connection: keep-alive ----》使用長連接
--------------------------------------------------------------------------------------------------------------------
HTTP 1.1 304 Not Modified ----》沒修改
Content-Type: application/x-javascript
Last-Modified : web,22**
Content-Encoding:gzip
更詳細的見http規范: http://www.w3.org/Protocols/rfc2616/rfc2616.html
1、減少HTTP請求
- 使用圖片地圖 一個圖片上面關聯多個URL,由點擊的位置決定目標URL,目的在于建設圖片數量
- CSS Sprites 講多個圖片合并成一幅圖片,圖片地圖中的圖片要連續,Css Sprites不需要
- 內聯圖片
- 合并腳本和樣式表 網站首頁平均應該使用6、7個腳本和1、2個樣式表
2、使用外部JavaScript和CSS
單純來說,內聯比外聯更快一些。
對于用戶訪問很少的頁面,比如注冊等,建議內聯。
對于用戶訪問較多的頁面,比如list或者商品詳情頁面等,建議外聯,瀏覽器可以使用緩存的組件。
對于重用性較高的組件,使用外聯
3、使用內容發布網絡
CDN(Content Delivery Network)內容分發網絡,讓用戶就近訪問頁面靜態組件
4、減少DNS查找
通常瀏覽器查詢一個給定的主機名的ip需要花費20-120毫秒。建議將頁面組件放在至少2個,但不超過4個的主機名下。
5、添加Expires或者Cache-Control頭
Expires和Cache-Control頭都用于瀏覽器可以使用本地緩存直至制定的時間,web服務器如apache,lighttpd,nginx等都有相應模塊可配置
6、精簡JavaScript
精簡代碼,將所有不必要的注釋和空白換行等移除??梢允褂?JSMin(http://crockford.com/javascript/jsmin)進行精簡。
7、壓縮組件
Accept-Encoding頭,一般只壓縮腳本和樣式表,圖片不需要,因為圖片通常都是壓縮過的。Apache 2.x使用mod_deflate模塊gzip壓縮
8、避免重定向
重定向使得html文檔到達前,頁面不會呈現任何內容。所以要減少重定向
9、將樣式表放在頂部
樣式表放在底部,瀏覽器為了在樣式表變化時不需要重繪頁面會阻止內容自頂向下逐步呈現。將CSS放在頂部,有利于瀏覽器從上向下顯示頁面。
推薦使用<link rel="stylesheet" href="common.css">方式,而不是import方式,因為import方式會導致組件下載的無序性,破壞了放在頂部的初衷。
10、移除重復腳本
由于團隊成員的長期維護,會遺留一定的重復腳本,需要定期清理
11、將腳本放在底部
瀏覽器遵從http規范并行的從每個主機名并行下載兩個組件。這樣可以有效提高下載的效率。但瀏覽器在下載腳本時時禁用并行下載的,因為腳本有可能修改頁面內容。瀏覽器會阻塞確保頁面恰當的布局。
12、配置ETag
13、避免CSS表達式
CSS表達式是實現的效果可以通過其他手段實現,并且風險更小。
14、使Ajax可緩存
Ajax只是實現了異步,避免頁面的重新加載,但是不意味著即時。所有一個用戶在操作后仍然要等待才能看到結果。一些緩存的原則也可以適用于ajax.
Ajax的POST要兩步,而GET只需要一步。所以盡量采用get方式。GET 方式可以更快響應,但是可能會有被瀏覽器緩存的問題,一般都需要加個隨機數來避免,POST 方式則不會。
15、Cookie
減少cookie中的信息,避免不重要的信息放在cookie中;對于圖片或者靜態服務器,使用cookie無關的域名,避免cookie的傳輸。
posted @
2011-04-08 10:59 liucs 閱讀(297) |
評論 (0) |
編輯 收藏
低耦合、高內聚
OOP設計原則主要提供了一個方向,使得我們的程序設計得更加合理,從而獲得更好的可擴展性、可維護性。主要包括以下幾個原則:
1、
OCP(Open-Closed Principle) 開放封閉原則。
對擴展開放,對修改關閉。即在不修改原有程序源碼的情況下對其進行擴展。實現開閉原則的關鍵就在于“抽象”。
“作為系統設計的抽象層,要預見所有可能的擴展,從而使得在任何擴展情況下,系統的抽象底層不需修改;同時,由于可以從抽象底層導出一個或多個新的具體實
現,可以改變系統的行為,因此系統設計對擴展是開放的。 ” 這個原則是OOP的基石,其他原則主要來實現本原則。
2、
SRP (Simple Responsibility Pinciple)單一職責原則。
一個類一般應該設計成只有一個職責,如果設計成具備很多職責,那么任何一個職責的改變都會引起這個類的修改,相關引用該類的代碼也可能受到影響。不同的職責或功能應該由不同的類來實現,這樣可以很好的控制變化帶來的影響粒度。
3、
DIP (Dependence Inversion Principle)依賴倒轉原則。
抽象不應該依賴于實現細節,實現細節應該依賴于抽象;高層不應該依賴于底層,都應該依賴于抽象。針對接口編程: 應該用接口或者抽象類聲明變量、方法參數、方法返回類型等。
4、
LSP (Liskov Substitution Principle)里氏代換原則。
子類型完全可以替換父類型,而不需要任何修改,并且獲得期望的結果。
5、
ISP (Interface Segregation Principle)接口隔離原則。
客戶端不應該可以訪問不需要的方法,這些不需要的方法是一種有害的耦合性。
所以應該設計多個專門接口而不是單個復雜的接口,客戶端僅依賴最小的接口類型。
6、
LoD (Law of Demeter)迪米特法則。
即最少知識原則。一個對象應當對其他對象有盡可能少的了解。只和最直接的類交互,對第三方可以通過轉達交互,從而減少對象間的耦合性。
7、
CARP (Composite/Aggregate Reuse Principle)合成/聚合復用原則。
多聚合、少繼承,實現復用性。聚合的復用是一種封閉性的復用,被復用者對復用者隱藏了自身細節,而繼承是一種開放性的復用,子類可以獲取父類型相關的細節,破壞了封閉性。
posted @
2011-03-31 14:07 liucs 閱讀(394) |
評論 (0) |
編輯 收藏
Java Reflection 是一種
內省機制,幫助程序在
運行時對自身及軟件環境進行檢查,并根據檢查得到的程序結構,改變自身的部分行為。
核心類為
java.lang.Class 類,抽象了程序的元數據,每一個類的元數據就是一個Class對象實例。這個Class實例是一個靜態實例,對應類的每一個實例都會關聯這個靜態實例。通過Class類可以查詢該類的方法、字段、接口、構造器等一系列信息。詳見下面。
對象回去自身對應的Class實例是通過繼承自Object類的getClass()方法;
對于基本類型,每一種也有一個名為class的靜態實例,如int.class double.class boolean.class;
對于數組類型,也有Object[].class, 注意 int[][].class==int[].class
判斷對象類型的接口:
String getName() 獲得類全名
Class getComponentType() 如果對象是數組,返回數據中元素的類類型
boolean isArray()
boolean isInterface()
boolean isPrimitive()
boolean isAnnotation()
###########################################################################################################
接口
java.lang.Class中定義的檢查接口的接口:
Class[] getInterfaces()
Class getSuperClass() 直系父類 ,對于Object、接口、void關鍵字、基本類型,返回null
boolean isAssignableFrom(Class cls) 該類是參數的類型或參數的父類型
boolean isInstance(Object obj) 該類是參數的實例或者參數的子類實例
Class類和Object類存在比較糾結的關系
Class.class.isIntance(Class.class) == true Class類的class實例是Class本身的實例
Class.class.isInstance(Object.class) == true
Object.class.isAssignableFrom(Class.class) == true
Object.class.isIntance(Class.class) == true
###########################################################################################################
java.lang.reflect部分類圖
###########################################################################################################
java.lang.reflect.Constructor
java.lang.Class中相關方法
Constructor getConstructor(Class[] parameterTypes)
Constructor getDeclaredConstructor(Class[]parameterTypes)
Constructor[] getConstructors()
Constructor[] getDeclaredConstructors()
java.lang.reflect.Constructor
Class getDeclaredClass()
Class[] getExceptionTypes()
int getModifiers()
String getName()
Class[] getParameterTypes()
Object newInstance(Object[] initArgs) 創建實例
對于數組,使用 java.lang.reflect.Array.newInstance(String.class,5)形式創建實例
###########################################################################################################
java.lang.reflect.Method
java.lang.Class類中定義了如下接口查詢一個類所具有的方法。
Method getMethod(String name,Class[]parameterTypes)
Method[] getMethods()
上述2個接口查詢繼承獲得和自身聲明的方法
Method getDeclaredMethod(String name,Class[]parameterTypes)
Method[] getDeclaredMethods()
上述2個接口查詢自身聲明的方法
java.lang.reflect.Method類定義的方法
Class getDeclaringClass() 聲明該方法的類實例
Class[] getExceptionTypes() 方法的異常類型
int getModifiers() 方法的可見性
String getName() 方法名
Class[] getParameterTypes() 方法參數類型
Class getReturnType() 方法返回類型
Object invoke(Object obj,Object[]args) 反射調用一個對象上面的該方法
###########################################################################################################
java.lang.reflect.Field
java.lang.Class類中關于Field的相關方法:
Field getField(String name)
Field[] getFields()
Field getDeclaredField(String name)
Field[] getDeclaredFields()
java.lang.relect.Field中主要方法
Class getType() 返回字段的Class
Class getDeclaringClass() 返回什么該字段的Class
String getName()
int getModifiers()
Object get(Object obj) 返回obj該字段的值
boolean getBoolean(Object obj)
void set(Object obj,Object value) 設置obj該字段的值
void setBoolean(Object obj,boolean value)
###########################################################################################################
java.lang.reflect.Modifier 字段或者方法的訪問性
static boolean isPublic(int mod)
static boolean isPrivate(int mod)
共包括以下:
public static native volatile protected transient
abstract synchronized strictfp private final
###########################################################################################################
動態加載
Class cls = Class.forName(String className);
Object obj = cls.newInstance();
動態加載機制使得可以避開編譯器類范圍的限制,常見場景是jdbc驅動。動態加載機制也是通過ClassLoader實現。
通過動態加載機制的類名并不是一般意義的類名,而是:
1、基本類型,首字母大寫,如 int -> I
2、引用類型,L+全類名,如 Ljava.lang.String
3、數組類型,[+***, 如[I, [Ljava.lang.String , [[I, [[Ljava.lang.String
注意:基本類型,不能通過Class.forName()加載,會拋出異常
posted @
2011-03-31 14:06 liucs 閱讀(329) |
評論 (0) |
編輯 收藏
Java在方法參數傳遞時:
1、對于基本類型,傳遞值
2、對于對象類型,傳遞對象引用
需要注意的是:對于上述兩種傳遞類型,在傳遞時都是拷貝傳遞,即值傳遞時拷貝出一個新值,引用
傳遞時拷貝出一個新的拷貝。
有時候也說Java只有值傳遞,意思是對于引用類型,傳遞引用的值。一個概念,不用糾纏。
在內存中對象類型可以看做兩塊,一塊是對象的引用,一塊是數據區。引用塊里面保存了數據區的地址。
看如下示例代碼:
1 public class Test {
2
3 public static void main(String[] args) {
4 // 值傳遞
5 int i = 1;
6 addInt1(i);
7 System.out.println(i);// 輸出1
8 addInt2(i);
9 System.out.println(i);// 輸出1
10
11 // 引用傳遞實例1
12 String str = "123";
13 modifyStr1(str);
14 System.out.println(str);// 輸出123
15
16 // 引用傳遞實例2
17 StringBuilder stringBuilder = new StringBuilder("123");
18 modifyStringBuilder(stringBuilder);
19 System.out.println(stringBuilder.toString());// 輸出123456
20 }
21
22 // 拷貝了新的值,原值不變
23 public static void addInt1(int i) {
24 i = 2;
25 }
26
27 // 拷貝了新的值,原值不變
28 public static void addInt2(int i) {
29 i++;
30 }
31
32 // 新的拷貝引用指向了一塊新數據區,原拷貝仍然指向原數據區
33 public static void modifyStr1(String str) {
34 str = "456";
35 }
36
37 // 新的拷貝引用仍然指向原數據區,但修改了原數據區的內容
38 public static void modifyStringBuilder(StringBuilder str) {
39 str.append("456");
40 }
41
42 }
posted @
2011-03-31 14:05 liucs 閱讀(304) |
評論 (0) |
編輯 收藏