摘要: 起因:在寫java的時候,經常遇到函數需要返回2個值或者3個值,java必須編寫一個Object,來封裝,但很多應用場景只是臨時使用,構建對象感覺殺雞用宰牛刀,而其他語言有比較好的實現方法。(當然通過指針引用可以解決一部分問題) 如:一般寫法:
Code high...
閱讀全文
摘要: java.util.concurrent包分成了三個部分,分別是:  ...
閱讀全文
不復制內容了,可以看戲如下鏈接,還是有很多值得看的東東,有空看下。~
http://terryblog.blog.51cto.com/1764499/547777
1.找到你的debug.keystore文件所在的路徑:
證書的一般路徑為:打開eclipse,選擇Windows———>Preference———>Android———>Build,其中Default debug keystore的值便是debug.keystore的路徑(windows的一般在 C:\Documents and Settings\當前用戶\.android下找到debug.keystore)
2.在命令提示符中執行: keytool -list -keystore debug.keystore (keytool是java一個命令,在%java_home%\bin里可以看到)
需要輸入密碼:android
然后就會得到MD5的值,進入
http://code.google.com/intl/zh-CN/android/add-ons/google-apis/maps-api-signup.html ,根據MD5值獲取MAPS API KEY(前提是你必須有一個google賬戶)
使input組件的絕對位置覆蓋select組件的選擇框,當select的狀態發生改變的時候,使用this.parentNode.nextSibling.value=this.value把select所選擇的值賦給input.
<HTML>
<HEAD>
<META http-equiv='Content-Type' content='text/html; charset=gb2312'>
<TITLE>可輸入的下拉框</TITLE>
</HEAD>
<BODY >
<div style="position:relative;">
<span style="margin-left:100px;width:18px;overflow:hidden;">
<select style="width:118px;margin-left:-100px" onchange="this.parentNode.nextSibling.value=this.value">
<option value="
<option value="
<option value="WEB開發者"> WEB開發者 </option>
</select></span><input name="box" style="width:100px;position:absolute;left:0px;">
</div>
</BODY></HTML>
單例創建模式是一個通用的編程習語。和多線程一起使用時,必需使用某種類型的同步。在努力創建更有效的代碼時,Java 程序員們創建了雙重檢查鎖定習語,將其和單例創建模式一起使用,從而限制同步代碼量。然而,由于一些不太常見的 Java 內存模型細節的原因,并不能保證這個雙重檢查鎖定習語有效。它偶爾會失敗,而不是總失敗。此外,它失敗的原因并不明顯,還包含 Java 內存模型的一些隱秘細節。這些事實將導致代碼失敗,原因是雙重檢查鎖定難于跟蹤。在本文余下的部分里,我們將詳細介紹雙重檢查鎖定習語,從而理解它在何處失效。
單例創建習語
要理解雙重檢查鎖定習語是從哪里起源的,就必須理解通用單例創建習語,如清單 1 中的闡釋:
清單 1. 單例創建習語
import java.util.*;
class Singleton
{
private static Singleton instance;
private Vector v;
private boolean inUse;
private Singleton()
{
v = new Vector();
v.addElement(new Object());
inUse = true;
}
public static Singleton getInstance()
{
if (instance == null) //1
instance = new Singleton(); //2
return instance; //3
}
}
|
此類的設計確保只創建一個 Singleton
對象。構造函數被聲明為 private
,getInstance()
方法只創建一個對象。這個實現適合于單線程程序。然而,當引入多線程時,就必須通過同步來保護 getInstance()
方法。如果不保護 getInstance()
方法,則可能返回 Singleton
對象的兩個不同的實例。假設兩個線程并發調用 getInstance()
方法并且按以下順序執行調用:
- 線程 1 調用
getInstance()
方法并決定 instance
在 //1 處為 null
。
- 線程 1 進入
if
代碼塊,但在執行 //2 處的代碼行時被線程 2 預占。
- 線程 2 調用
getInstance()
方法并在 //1 處決定 instance
為 null
。
- 線程 2 進入
if
代碼塊并創建一個新的 Singleton
對象并在 //2 處將變量 instance
分配給這個新對象。
- 線程 2 在 //3 處返回
Singleton
對象引用。
- 線程 2 被線程 1 預占。
- 線程 1 在它停止的地方啟動,并執行 //2 代碼行,這導致創建另一個
Singleton
對象。
- 線程 1 在 //3 處返回這個對象。
結果是 getInstance()
方法創建了兩個 Singleton
對象,而它本該只創建一個對象。通過同步 getInstance()
方法從而在同一時間只允許一個線程執行代碼,這個問題得以改正,如清單 2 所示:
清單 2. 線程安全的 getInstance() 方法
public static synchronized Singleton getInstance()
{
if (instance == null) //1
instance = new Singleton(); //2
return instance; //3
}
|
清單 2 中的代碼針對多線程訪問 getInstance()
方法運行得很好。然而,當分析這段代碼時,您會意識到只有在第一次調用方法時才需要同步。由于只有第一次調用執行了 //2 處的代碼,而只有此行代碼需要同步,因此就無需對后續調用使用同步。所有其他調用用于決定 instance
是非 null
的,并將其返回。多線程能夠安全并發地執行除第一次調用外的所有調用。盡管如此,由于該方法是 synchronized
的,需要為該方法的每一次調用付出同步的代價,即使只有第一次調用需要同步。
為使此方法更為有效,一個被稱為雙重檢查鎖定的習語就應運而生了。這個想法是為了避免對除第一次調用外的所有調用都實行同步的昂貴代價。同步的代價在不同的 JVM 間是不同的。在早期,代價相當高。隨著更高級的 JVM 的出現,同步的代價降低了,但出入 synchronized
方法或塊仍然有性能損失。不考慮 JVM 技術的進步,程序員們絕不想不必要地浪費處理時間。
因為只有清單 2 中的 //2 行需要同步,我們可以只將其包裝到一個同步塊中,如清單 3 所示:
清單 3. getInstance() 方法
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) {
instance = new Singleton();
}
}
return instance;
}
|
清單 3 中的代碼展示了用多線程加以說明的和清單 1 相同的問題。當 instance
為 null
時,兩個線程可以并發地進入 if
語句內部。然后,一個線程進入 synchronized
塊來初始化 instance
,而另一個線程則被阻斷。當第一個線程退出 synchronized
塊時,等待著的線程進入并創建另一個 Singleton
對象。注意:當第二個線程進入 synchronized
塊時,它并沒有檢查 instance
是否非 null
。
雙重檢查鎖定
為處理清單 3 中的問題,我們需要對 instance
進行第二次檢查。這就是“雙重檢查鎖定”名稱的由來。將雙重檢查鎖定習語應用到清單 3 的結果就是清單 4 。
清單 4. 雙重檢查鎖定示例
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
if (instance == null) //2
instance = new Singleton(); //3
}
}
return instance;
}
|
雙重檢查鎖定背后的理論是:在 //2 處的第二次檢查使(如清單 3 中那樣)創建兩個不同的 Singleton
對象成為不可能。假設有下列事件序列:
- 線程 1 進入
getInstance()
方法。
- 由于
instance
為 null
,線程 1 在 //1 處進入 synchronized
塊。
- 線程 1 被線程 2 預占。
- 線程 2 進入
getInstance()
方法。
- 由于
instance
仍舊為 null
,線程 2 試圖獲取 //1 處的鎖。然而,由于線程 1 持有該鎖,線程 2 在 //1 處阻塞。
- 線程 2 被線程 1 預占。
- 線程 1 執行,由于在 //2 處實例仍舊為
null
,線程 1 還創建一個 Singleton
對象并將其引用賦值給 instance
。
- 線程 1 退出
synchronized
塊并從 getInstance()
方法返回實例。
- 線程 1 被線程 2 預占。
- 線程 2 獲取 //1 處的鎖并檢查
instance
是否為 null
。
- 由于
instance
是非 null
的,并沒有創建第二個 Singleton
對象,由線程 1 創建的對象被返回。
雙重檢查鎖定背后的理論是完美的。不幸地是,現實完全不同。雙重檢查鎖定的問題是:并不能保證它會在單處理器或多處理器計算機上順利運行。
雙重檢查鎖定失敗的問題并不歸咎于 JVM 中的實現 bug,而是歸咎于 Java 平臺內存模型。內存模型允許所謂的“無序寫入”,這也是這些習語失敗的一個主要原因。
無序寫入
為解釋該問題,需要重新考察上述清單 4 中的 //3 行。此行代碼創建了一個 Singleton
對象并初始化變量 instance
來引用此對象。這行代碼的問題是:在 Singleton
構造函數體執行之前,變量 instance
可能成為非 null
的。
什么?這一說法可能讓您始料未及,但事實確實如此。在解釋這個現象如何發生前,請先暫時接受這一事實,我們先來考察一下雙重檢查鎖定是如何被破壞的。假設清單 4 中代碼執行以下事件序列:
- 線程 1 進入
getInstance()
方法。
- 由于
instance
為 null
,線程 1 在 //1 處進入 synchronized
塊。
- 線程 1 前進到 //3 處,但在構造函數執行之前,使實例成為非
null
。
- 線程 1 被線程 2 預占。
- 線程 2 檢查實例是否為
null
。因為實例不為 null,線程 2 將 instance
引用返回給一個構造完整但部分初始化了的 Singleton
對象。
- 線程 2 被線程 1 預占。
- 線程 1 通過運行
Singleton
對象的構造函數并將引用返回給它,來完成對該對象的初始化。
此事件序列發生在線程 2 返回一個尚未執行構造函數的對象的時候。
為展示此事件的發生情況,假設為代碼行 instance =new Singleton();
執行了下列偽代碼: instance =new Singleton();
mem = allocate(); //Allocate memory for Singleton object.
instance = mem; //Note that instance is now non-null, but
//has not been initialized.
ctorSingleton(instance); //Invoke constructor for Singleton passing
//instance.
|
這段偽代碼不僅是可能的,而且是一些 JIT 編譯器上真實發生的。執行的順序是顛倒的,但鑒于當前的內存模型,這也是允許發生的。JIT 編譯器的這一行為使雙重檢查鎖定的問題只不過是一次學術實踐而已。
為說明這一情況,假設有清單 5 中的代碼。它包含一個剝離版的 getInstance()
方法。我已經刪除了“雙重檢查性”以簡化我們對生成的匯編代碼(清單 6)的回顧。我們只關心 JIT 編譯器如何編譯 instance=new Singleton();
代碼。此外,我提供了一個簡單的構造函數來明確說明匯編代碼中該構造函數的運行情況。
清單 5. 用于演示無序寫入的單例類
class Singleton
{
private static Singleton instance;
private boolean inUse;
private int val;
private Singleton()
{
inUse = true;
val = 5;
}
public static Singleton getInstance()
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
|
清單 6 包含由 Sun JDK 1.2.1 JIT 編譯器為清單 5 中的 getInstance()
方法體生成的匯編代碼。
清單 6. 由清單 5 中的代碼生成的匯編代碼
;asm code generated for getInstance
054D20B0 mov eax,[049388C8] ;load instance ref
054D20B5 test eax,eax ;test for null
054D20B7 jne 054D20D7
054D20B9 mov eax,14C0988h
054D20BE call 503EF8F0 ;allocate memory
054D20C3 mov [049388C8],eax ;store pointer in
;instance ref. instance
;non-null and ctor
;has not run
054D20C8 mov ecx,dword ptr [eax]
054D20CA mov dword ptr [ecx],1 ;inline ctor - inUse=true;
054D20D0 mov dword ptr [ecx+4],5 ;inline ctor - val=5;
054D20D7 mov ebx,dword ptr ds:[49388C8h]
054D20DD jmp 054D20B0
|
注: 為引用下列說明中的匯編代碼行,我將引用指令地址的最后兩個值,因為它們都以 054D20
開頭。例如,B5
代表 test eax,eax
。
匯編代碼是通過運行一個在無限循環中調用 getInstance()
方法的測試程序來生成的。程序運行時,請運行 Microsoft Visual C++ 調試器并將其附到表示測試程序的 Java 進程中。然后,中斷執行并找到表示該無限循環的匯編代碼。
B0
和 B5
處的前兩行匯編代碼將 instance
引用從內存位置 049388C8
加載至 eax
中,并進行 null
檢查。這跟清單 5 中的 getInstance()
方法的第一行代碼相對應。第一次調用此方法時,instance
為 null
,代碼執行到 B9
。BE
處的代碼為 Singleton
對象從堆中分配內存,并將一個指向該塊內存的指針存儲到 eax
中。下一行代碼,C3
,獲取 eax
中的指針并將其存儲回內存位置為 049388C8
的實例引用。結果是,instance
現在為非 null
并引用一個有效的 Singleton
對象。然而,此對象的構造函數尚未運行,這恰是破壞雙重檢查鎖定的情況。然后,在 C8
行處,instance
指針被解除引用并存儲到 ecx
。CA
和 D0
行表示內聯的構造函數,該構造函數將值 true
和 5
存儲到 Singleton
對象。如果此代碼在執行 C3
行后且在完成該構造函數前被另一個線程中斷,則雙重檢查鎖定就會失敗。
不是所有的 JIT 編譯器都生成如上代碼。一些生成了代碼,從而只在構造函數執行后使 instance
成為非 null
。針對 Java 技術的 IBM SDK 1.3 版和 Sun JDK 1.3 都生成這樣的代碼。然而,這并不意味著應該在這些實例中使用雙重檢查鎖定。該習語失敗還有一些其他原因。此外,您并不總能知道代碼會在哪些 JVM 上運行,而 JIT 編譯器總是會發生變化,從而生成破壞此習語的代碼。
雙重檢查鎖定:獲取兩個
考慮到當前的雙重檢查鎖定不起作用,我加入了另一個版本的代碼,如清單 7 所示,從而防止您剛才看到的無序寫入問題。
清單 7. 解決無序寫入問題的嘗試
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
Singleton inst = instance; //2
if (inst == null)
{
synchronized(Singleton.class) { //3
inst = new Singleton(); //4
}
instance = inst; //5
}
}
}
return instance;
}
|
看著清單 7 中的代碼,您應該意識到事情變得有點荒謬。請記住,創建雙重檢查鎖定是為了避免對簡單的三行 getInstance()
方法實現同步。清單 7 中的代碼變得難于控制。另外,該代碼沒有解決問題。仔細檢查可獲悉原因。
此代碼試圖避免無序寫入問題。它試圖通過引入局部變量 inst
和第二個 synchronized
塊來解決這一問題。該理論實現如下:
- 線程 1 進入
getInstance()
方法。
- 由于
instance
為 null
,線程 1 在 //1 處進入第一個 synchronized
塊。
- 局部變量
inst
獲取 instance
的值,該值在 //2 處為 null
。
- 由于
inst
為 null
,線程 1 在 //3 處進入第二個 synchronized
塊。
- 線程 1 然后開始執行 //4 處的代碼,同時使
inst
為非 null
,但在 Singleton
的構造函數執行前。(這就是我們剛才看到的無序寫入問題。)
- 線程 1 被線程 2 預占。
- 線程 2 進入
getInstance()
方法。
- 由于
instance
為 null
,線程 2 試圖在 //1 處進入第一個 synchronized
塊。由于線程 1 目前持有此鎖,線程 2 被阻斷。
- 線程 1 然后完成 //4 處的執行。
- 線程 1 然后將一個構造完整的
Singleton
對象在 //5 處賦值給變量 instance
,并退出這兩個 synchronized
塊。
- 線程 1 返回
instance
。
- 然后執行線程 2 并在 //2 處將
instance
賦值給 inst
。
- 線程 2 發現
instance
為非 null
,將其返回。
這里的關鍵行是 //5。此行應該確保 instance
只為 null
或引用一個構造完整的 Singleton
對象。該問題發生在理論和實際彼此背道而馳的情況下。
由于當前內存模型的定義,清單 7 中的代碼無效。Java 語言規范(Java Language Specification,JLS)要求不能將 synchronized
塊中的代碼移出來。但是,并沒有說不能將 synchronized
塊外面的代碼移入 synchronized
塊中。
JIT 編譯器會在這里看到一個優化的機會。此優化會刪除 //4 和 //5 處的代碼,組合并且生成清單 8 中所示的代碼。
清單 8. 從清單 7 中優化來的代碼。
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
Singleton inst = instance; //2
if (inst == null)
{
synchronized(Singleton.class) { //3
//inst = new Singleton(); //4
instance = new Singleton();
}
//instance = inst; //5
}
}
}
return instance;
}
|
如果進行此項優化,您將同樣遇到我們之前討論過的無序寫入問題。
用 volatile 聲明每一個變量怎么樣?
另一個想法是針對變量 inst
以及 instance
使用關鍵字 volatile
。根據 JLS(參見 參考資料),聲明成 volatile
的變量被認為是順序一致的,即,不是重新排序的。但是試圖使用 volatile
來修正雙重檢查鎖定的問題,會產生以下兩個問題:
- 這里的問題不是有關順序一致性的,而是代碼被移動了,不是重新排序。
- 即使考慮了順序一致性,大多數的 JVM 也沒有正確地實現
volatile
。
第二點值得展開討論。假設有清單 9 中的代碼:
清單 9. 使用了 volatile 的順序一致性
class test
{
private volatile boolean stop = false;
private volatile int num = 0;
public void foo()
{
num = 100; //This can happen second
stop = true; //This can happen first
//...
}
public void bar()
{
if (stop)
num += num; //num can == 0!
}
//...
}
|
根據 JLS,由于 stop
和 num
被聲明為 volatile
,它們應該順序一致。這意味著如果 stop
曾經是 true
,num
一定曾被設置成 100
。盡管如此,因為許多 JVM 沒有實現 volatile
的順序一致性功能,您就不能依賴此行為。因此,如果線程 1 調用 foo
并且線程 2 并發地調用 bar
,則線程 1 可能在 num
被設置成為 100
之前將 stop
設置成 true
。這將導致線程見到 stop
是 true
,而 num
仍被設置成 0
。使用 volatile
和 64 位變量的原子數還有另外一些問題,但這已超出了本文的討論范圍。有關此主題的更多信息,請參閱 參考資料。
解決方案
底線就是:無論以何種形式,都不應使用雙重檢查鎖定,因為您不能保證它在任何 JVM 實現上都能順利運行。JSR-133 是有關內存模型尋址問題的,盡管如此,新的內存模型也不會支持雙重檢查鎖定。因此,您有兩種選擇:
- 接受如清單 2 中所示的
getInstance()
方法的同步。
- 放棄同步,而使用一個
static
字段。
選擇項 2 如清單 10 中所示
清單 10. 使用 static 字段的單例實現
class Singleton
{
private Vector v;
private boolean inUse;
private static Singleton instance = new Singleton();
private Singleton()
{
v = new Vector();
inUse = true;
//...
}
public static Singleton getInstance()
{
return instance;
}
}
|
清單 10 的代碼沒有使用同步,并且確保調用 static getInstance()
方法時才創建 Singleton
。如果您的目標是消除同步,則這將是一個很好的選擇。
String 不是不變的
鑒于無序寫入和引用在構造函數執行前變成非 null
的問題,您可能會考慮 String
類。假設有下列代碼:
private String str;
//...
str = new String("hello");
|
String
類應該是不變的。盡管如此,鑒于我們之前討論的無序寫入問題,那會在這里導致問題嗎?答案是肯定的。考慮兩個線程訪問 String str
。一個線程能看見 str
引用一個 String
對象,在該對象中構造函數尚未運行。事實上,清單 11 包含展示這種情況發生的代碼。注意,這個代碼僅在我測試用的舊版 JVM 上會失敗。IBM 1.3 和 Sun 1.3 JVM 都會如期生成不變的 String
。
清單 11. 可變 String 的例子
class StringCreator extends Thread
{
MutableString ms;
public StringCreator(MutableString muts)
{
ms = muts;
}
public void run()
{
while(true)
ms.str = new String("hello"); //1
}
}
class StringReader extends Thread
{
MutableString ms;
public StringReader(MutableString muts)
{
ms = muts;
}
public void run()
{
while(true)
{
if (!(ms.str.equals("hello"))) //2
{
System.out.println("String is not immutable!");
break;
}
}
}
}
class MutableString
{
public String str; //3
public static void main(String args[])
{
MutableString ms = new MutableString(); //4
new StringCreator(ms).start(); //5
new StringReader(ms).start(); //6
}
}
|
此代碼在 //4 處創建一個 MutableString
類,它包含了一個 String
引用,此引用由 //3 處的兩個線程共享。在行 //5 和 //6 處,在兩個分開的線程上創建了兩個對象 StringCreator
和 StringReader
。傳入一個 MutableString
對象的引用。StringCreator
類進入到一個無限循環中并且使用值“hello”在 //1 處創建 String
對象。StringReader
也進入到一個無限循環中,并且在 //2 處檢查當前的 String
對象的值是不是 “hello”。如果不行,StringReader
線程打印出一條消息并停止。如果 String
類是不變的,則從此程序應當看不到任何輸出。如果發生了無序寫入問題,則使 StringReader
看到 str
引用的惟一方法絕不是值為“hello”的 String
對象。
在舊版的 JVM 如 Sun JDK 1.2.1 上運行此代碼會導致無序寫入問題。并因此導致一個非不變的 String
。
結束語
為避免單例中代價高昂的同步,程序員非常聰明地發明了雙重檢查鎖定習語。不幸的是,鑒于當前的內存模型的原因,該習語尚未得到廣泛使用,就明顯成為了一種不安全的編程結構。重定義脆弱的內存模型這一領域的工作正在進行中。盡管如此,即使是在新提議的內存模型中,雙重檢查鎖定也是無效的。對此問題最佳的解決方案是接受同步或者使用一個 static field
。
薪水族如何“錢滾錢” 教你用2萬賺到1000萬
工薪族月薪2000元的理財竅門
在有很多的大學生都是在畢業以后選擇留在自己上學的城市,一來對城市有了感情,二來也希望能在大的城市有所
發展,而現在很多大城市勞動力過剩,大學生想找到一個自己喜歡又有較高收入的職位已經變得非常難,很多剛畢業的朋友的月收入都可能徘徊在2000元人民幣左右,如果您是這樣的情況,讓我們來核算一下,如何利用手中的有限資金來進行理財。如果您是單身一人,月收入在2000人民幣,又沒有其他的獎金分紅等收入,那年收入就固定在25000元左右。如何來支配這些錢呢?
生活費占收入30%-40%
首先,你要拿出每個月必須支付的生活費。如房租、水電、通訊費、柴米油鹽等,這部分約占收入三分之一。它們是你生活中不可或缺的部分,滿足你最基本的物質需求。離開了它們,你就會像魚兒離開了水一樣無法生活,所以無論如何,請你先從收入中抽出這部分,不要動用。
儲蓄占收入10%-20%
其次,是自己用來儲蓄的部分,約占收入的10%-20%。很多人每次也都會在月初存錢,但是到了月底的時候,往往就變成了泡沫,存進去的大部分又取出來了,而且是不知不覺的,好像憑空消失了一樣,總是在自己喜歡的衣飾、雜志、CD或朋友聚會上不加以節制。你要自己提醒自己,起碼,你的存儲能保證你3個月的基本生活。要知道,現在很多公司動輒減薪裁員。如果你一點儲蓄都沒有,一旦
工作發生了變動,你將會非常被動。
而且這3個月的收入可以成為你的定心丸,工作實在干得不開心了,忍無可忍無需再忍時,你可以瀟灑地對老板說聲“拜拜”。想想可以不用受你不喜歡的工作和人的氣,是多么開心的事啊。所以,無論如何,請為自己留條退路。
活動資金占收入30%~40%
剩下的這部分錢,約占收入的三分之一。可以根據自己當時的生活目標,側重地花在不同的地方。譬如“五一”、“十一”可以安排
旅游;服裝打折時可以購進自己心儀已久的牌子貨;還有平時必不可少的購買CD、朋友聚會的開銷。這樣花起來心里有數,不會一下子把錢都用完。
最關鍵的是,即使一發薪水就把這部分用完了,也可當是一次教訓,可以懲罰自己一個月內什么都不能再干了(就當是收入全部支出了吧),印象會很深刻而且有效。
除去吃、穿、住、行以及其他的消費外,再怎么節省,估計您現在的狀況,一年也只有10000元的積蓄,想來這些都是剛畢業的絕大部分學生所面臨的實際情況。如何讓錢生錢是大家想得最多的事情,然而,畢竟收入有限,很多想法都不容易實現,
建議處于這個階段的朋友,最重要的是開源,節流只是我們生活工作的一部分,就像大廈的基層一樣。而最重要的是怎樣財源滾滾、開源有道,為了達到一個新目標,你必須不斷進步以求發展,培養自己的實力以求進步,這才是真正的生財之道。可以安心地發展自己的事業,積累自己的經驗,充實自己,使自己不斷地提高,才會有好的發展,要相信“機會總是給有準備的人”。
當然,既然有了些許積蓄,也不能讓它閑置,我們建議把1萬元分為5份,分成5個2000元,分別作出適當的投資安排。這樣,家庭不會出現用錢危機,并可以獲得最大的收益。
(1)用2000元買國債,這是回報率較高而又很保險的一種投資。
(2)用2000元買保險。以往人們的保險意識很淡薄,實際上購買保險也是一種較好的投資方式,而且保險金不在利息稅征收之列。尤其是各壽險公司都推出了兩全型險種,增加了有關“權益轉換”的條款,即一旦銀行利率上升,
客戶可在保險公司
出售的險種中進行轉換,并獲得保險公司給予的一定的價格折扣、免予核保等
優惠政策。
(3)用2000元買股票。這是一種風險最大的投資,當然風險與收益是并存的,只要選擇得當,會帶來理想的投資回報。除股票外,期貨、投資債券等都屬這一類。不過,參與這類投資,要求有相應的行業知識和較強的風險意識。
(4)用2000元存定期存款,這是一種幾乎沒有風險的投資方式,也是未來對家庭生活的一種保障。
(5)用2000元存活期存款,這是為了應急之用。如家里臨時急需用錢,有一定數量的活期儲蓄存款可解燃眉之急,而且存取又很方便。
這種方法是許多人經過多年嘗試后總結出的一套成功的理財經驗。當然,各個家庭可以根據不同情況,靈活使用。
正確理財三個觀念
建立理財觀念一:理財是一件正大光明的事,“你不理財,財不理你”。
建立理財觀念二:理財要從現在開始,并長期堅持。
建立理財觀念三:理財目的是“梳理財富,增值生活”。
理財四個誤區
理財觀念誤區一:我沒財可理;
理財觀念誤區二:我不需要理財;
理財觀念誤區三:等我有了錢再理財;
理財觀念誤區四:會理財不如會掙錢。
理財的五大目標
目標一:獲得資產增值;
目標二:保證資金安全;
目標三:防御意外事故;
目標四:保證老有所養;
目標五:提供贍養父母及撫養教育子女的基金。
--------------------精彩閱讀推薦--------------------
【500強企業的薪水有多高?】
全球500強大企業的薪水實情大揭密
不一定要是自己的offer letter上的數據,凡是能夠確認比較準確的公司薪水都可補充。補充的話最好說明職位、本碩區別、多少個月工資、獎金。寶潔:本7200、研8200、博9700,均14個月,另有交通補助,區域補助等,CBD,marketing每幾個月漲20%-30%不定。
【工薪族的你跑贏通脹了嗎?】
工薪族理財跑贏通脹 開源節流資產合理配備
龍先生家是典型的工薪階層。龍先生47歲,是某大型企業的技術師,年收入5.5萬元,購買了各類基本保險。太太42歲,是某商場的合同工,年收入4萬元,購買了基本的社會保險。兩人均在單位吃中午飯,搭班車上下班。兒子16歲,尚在讀高中。
【怎樣才能錢生錢?】
“階梯存儲”應對利率調整 學三招輕松錢生錢
當前,儲蓄依然在居民理財的投資組合中占據著重要地位,但在當前的加息周期內,一些人因缺乏科學的儲蓄理財規劃而損失利息收入。理財專家建議,進入加息周期,為了使儲蓄理財能賺取更多的利息收入,儲戶應在存款期限、存款金額和存款方式上注意以下幾點。
【爺們的臉往哪擱!】
女人太會賺錢也是錯? 爺們兒的臉往哪擱
女人財大就氣粗?別偏激,妻子賺錢自己也是受益者,所以首先心態放平和些,別太執著于傳統的思維和他人的看法。會不會賺錢是女人衡量男人的重要標尺。男人沒錢,女人覺得沒有面子,不愿提及她的男人;有錢男人不怕提及他女人,無論漂亮與否,只要不給他戴綠帽子。
說起精致,最容易想起的詞大概是瓷器了,但這個詞用到程序員身上,肯定讓很多人覺得摸不著頭腦,在詳述"精致"這個詞以前,還是先來看一個"破窗理論",讓我們真正的理解"精致"的概念。
最早的"破窗理論",也稱"破窗謬論",源自于一位經濟學家黑茲利特(也有人說源于法國19世紀經濟學家巴斯夏),用來指出"破壞創造財富"的概念,以徹底地否定凱恩斯主義的政府干預政策。但后來美國斯坦福大學心理學家詹巴斗和犯罪學家凱琳也提出了相應的"破窗理論"。
心理學家詹巴斗進行了一項試驗,他把兩輛一模一樣的汽車分別停放在帕羅阿爾托的中產階級社區和相對雜亂的布朗克斯街區。對停在布朗克斯街區的那一輛,他摘掉了車牌,并且把頂棚打開,結果不到一天就被人偷走了;而停放在帕羅阿爾托的那一輛,停了一個星期也無人問津。后來,詹巴斗用錘子把這輛車的玻璃敲了個大洞,結果僅僅過了幾個小時車就不見了。
而犯罪學家凱琳曾注意到一個問題:在她上班的路旁,有一座非常漂亮的大樓,有一天,她注意到樓上有一窗子的玻璃被打破了,那扇破窗與整座大樓的整潔美麗極不調諧,顯得格外的刺眼。又過了一段時間,她驚奇地發現:那扇破窗不但沒得到及時的維修,反而又增加了幾個帶爛玻璃的窗子……這一發現使她的心中忽有所悟:如果有人打壞了一個建筑物的窗戶玻璃,而這扇窗戶又得不到及時維修的話,別人就可能受到某些暗示性的縱容去打爛更多的玻璃。久而久之,這些破窗戶就給人造成一種無序的感覺;其結果是:在這種麻木不仁的氛圍中,犯罪就會滋生。這就是凱琳著名的"破窗理論"。
后來的"破窗理論",已經突破原有經濟學上的概念,有了新的意義:殘缺不全的東西更容易遭受到別人的破壞。前面的汽車和窗戶都表明了這一點。
其實作為程序員開發軟件也是一樣,可能有十種好的方法去寫一個功能,一個類,但同時可能會有一百種更快捷但不好的方法去做同樣的事情,很多程序員會因為各種原因,如時間壓力,工作強度,技術水平等一系列問題選擇了后者而非前者。同樣的事情還發生在維護和修改階段,當看到別人的代碼寫的隨意,不好時,那么自然就會沿著別人的方向走下去,結果就是產生出更多不好的代碼,這是在代碼開發中的一個典型"破窗理論"的體現。
承認一點,現實世界是不完美,特別是開發中,因為時間,精力,能力等各種因素,我們始終是要打破一些窗戶,但是卻要記住兩點:
1.一個月前多打破了一扇窗戶,結果一個月就會打破10 扇甚至更多的窗戶。
2.如果打破了一扇窗戶,就要記住,遲早應該將它補上。
因為各方面的原因,一個程序員也許不能做到精致的代碼,但是如果一個程序員不想去做精致的代碼,那么又何必選擇軟件開發呢?
最近有Java解壓縮的需求,java.util.zip實在不好用,對中文支持也不行。所以選擇了強大的TrueZIP,使用時遇到了一個問題,做個記錄。
解壓縮代碼如下:
ArchiveDetector detector = new DefaultArchiveDetector(ArchiveDetector.ALL,
new Object[] { "zip", new CheckedZip32Driver("GBK") } );
File zipFile = new File("zipFile", detector);
File dst = new File("dst");
// 解壓縮
zipFile.copyAllTo(dst);
代碼十分簡潔,注意這個File是
de.schlichtherle.io.File
不是
java.io.File
當處理完業務要刪除這個Zip File時,問題出現了:
這個文件刪不掉!!!
把自己的代碼檢查了好久,確認沒問題后,開始從TrueZIP下手,發現它有特殊的地方的,是提示過的:
File file = new File(“archive.zip”); // de.schlichtherle.io.File!
Please do not do this instead:
de.schlichtherle.io.File file = new de.schlichtherle.io.File(“archive.zip”);
This is for the following reasons:
1.Accidentally using java.io.File and de.schlichtherle.io.File instances referring to the same path concurrently will result in erroneous behaviour and may even cause loss of data! Please refer to the section “Third Party Access” in the package Javadoc of de.schlichtherle.io for for full details and workarounds.
2.A de.schlichtherle.io.File subclasses java.io.File and thanks to polymorphism can be used everywhere a java.io.File could be used.
原來兩個File不能交叉使用,搞清楚原因了,加這么一句代碼搞定。
zipFile.deleteAll();
http://www.tkk7.com/Files/lsbwahaha/ANTLR_info.pdf
antlr簡介
目前的ANTLR支持的語法層的選項主要包括:
語言選項(Language)、
輸出選項(output)、
回溯選項(backtrack)、
記憶選項 (memorize)、
記號詞庫(tokenVocab)、
重寫選項(rewrite)、
超類選項(superClass)、
過濾選項(Filter)、
AST標簽類型(ASTLabelType)
K選項
/**
//一些寫法
k=2;
backtrack=true;
memoize=true;
*/
1. 語言選項 language
語言選項指定了ANTLR將要產生的代碼的目標語言,默認情況下該選項設置為了Java。需要注意的是,ANTLR中的嵌入的動作必須要使用目標語言來寫。
grammar T;
options {
language=Java;
}
ANTLR使用了特有的基于字串模板(StringTemplate-based)代碼生成器,構建一個新的目標語言顯得較為簡單,因此我們可以構建多種
語言,諸如Java,C,C++,C#,Python,Objective-C,Ruby等等。語言選項讓ANNTLR去模板目錄(例如 org/antlr/codegen/templates/Java or org/antlr/codegen/templates/C)下尋找合適的模板,并使用模板來構建語言。該目錄下包含大量的模板,我們可以向其中加入其
他的模板以滿足我們的需求。
2. 輸出選項 output
輸出選項控制了ANTLR輸出的數據結構,目前支持兩種輸出:抽象語法樹——AST(Abstract Syntax Trees)和字串模板(StringTemplates)——template。當output這個選項被設置后,所有的規則都被輸出成了AST或者 template。
grammar T;
options {
output=AST;
}
3. 回溯選項backtrack
當回溯選項打開的時候,在執行一個LL(K)失敗的時候,ANTLR會返回至LL(K)開始而嘗試其他的規則。
4. 記憶選項 (memorize)
memoize選項打開以后,每條解析方法(Paser Method)開始之前,ANTLR會首先檢測以前的嘗試結果,并在該方法執行完成之后記錄該規則是否執行成功。但是注意,對于單條的規則打開此選項經常比在全局上打開該規則效率更高。
5. 記號詞庫(tokenVocab)
說白了就是output輸出目錄中的XX.tokens文件中的定義可以方便的給 大型工程中多個.g中的符號同步更新。
大型的工程中常常利用AST作為中間產物對輸入進行多次分析并最終生成代碼。對AST的遍歷時需要經常使用樹語法(tree grammar),而tree grammar中經常需要將符號與其他的文件中的符號進行同步或者更新。tokenVocab實現了這個功能。
例如我們定義了下面的一個語法文件:
grammar P;
options {
output=AST;
}
expr: INT ('+' ^ INT)* ;
INT : '0'..'9' +;
WS : ' ' | '\r' | '\n' ;
利用該文件生成了一個標記:P.token,并生成了語法樹(AST)。這時我們需要一個用于遍歷該AST的tree grammar,并通過tree grammar 中的tokenVocab選項來向其中更新tokens:
tree grammar Dump;
options {
tokenVocab=P;
ASTLabelType=CommonTree;
}
expr: ^( '+' expr {System.out.print('+' );} expr )
| INT {System.out.print($INT.text);}
;
編譯tree grammar的時候ANTLR默認會在當前目錄下尋找.token文件,我們可以通過-lib選項來設置用于尋找.token文件的目錄,例如:
java org.antlr.Tool -lib . Dump.g
6. 重寫選項(rewrite)
通過重寫選項可以改變ANTLR對輸入的默認處理規則,一般用在輸出為template的情況下。將該選項使能之后,ANTLR將一般的輸入直接拷貝至輸出,而將適于模板重寫規則的輸入做其他的處理。
7. 超類選項(superClass)
用于指定一個超類。
8. 過濾選項(Filter)
9. AST標簽類型(ASTLabelType)
10.
K選項
K選項用于限制對LL(K)進行語法分析的次數,從而提高了ANTLR的解析速度。K只能為*或者數字,默認為*。
屬性和動作
動作(Actions)實際上是用目標語言寫成的、嵌入到規則中的代碼(以花括號包裹)。它們通常直接操作輸入的標號,但是他們也可以用來調用相應的外部代碼。屬性,到目前為止我的理解還不多,感覺像是C++中類里面的成員,一會看完應該會更清楚一些。
1. 語法動作(Grammar Actions)
動作(Actions)是指嵌在語法中的、用目標語言寫成的代碼片段。ANTLR則把這些代碼(除了用$或%標記的以外)逐字地插入到生成的識別器中。
動作可以放到規則的外邊,也可以嵌入到某條規則當中。當動作位于規則之外時候,這些動作同城定義了一些全局的或者是類的成員(變量或者成員函數);而當其嵌入規則之中時,則用于執行某些特定的命令,這些命令在識別器識別了其預訂的字符的時候就會開始執行。例如下面的例子:
parser grammar T;
@header {
package p;
}
@members {
int i;
public TParser(TokenStream input, int foo) {
this(input);
i = foo;
}
}
a[int x] returns [int y]
@init {int z=0;}
@after {System.out.println("after matching rule; before finally");}
: {《action1》} A {《action2 》}
;
catch[RecognitionException re] {
System.err.println("error");
}
finally { 《do-this-no-matter-what 》 }
從中可以看出,前面的兩個動作,@head and @members是兩個處于規則之外的全局的動作,定義了一些變量和類;而后兩個則分別在a這個規則的前后執行(@init在前,@after在后,這個在前面提到過)。
這里針對兩種類型詳細敘述。
antlr簡介