Java Thread: run() vs start()
剛在寫ANDROID,在使用到 audioRecord,所以用到了thread!
突然忘記要用run呢? 還是要用start?
查了一下資料,才找出差異性。
使用run呢,他是循序性的,也就是說他會跑完run裡面的程式,才會跳脫。
而start不是。
用個簡單的範例說明一下:
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("t1");
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("t2");
}
}
});
上面我們宣告了2個thread,一個是t1,一個是t2。
都做完一千次才會停止。
他們分別會去印出自己是t1還是t2。
如果我們是使用run,如下:
t1.run();
t2.run();
那麼印出來的值一定是像下面一樣
t1 -> t1 -> t1 -> .........t1 -> t2 -> t2 -> ......t2 會先印完1000次的t1,才開始印1000次的t2。 但如果我們是使用start,如下:
t1.start();
t2.start();
結果就會相互交叉,
可能是
t1->
t1->
t2->
t1->
t2..........
以此類推。
C++: Reference (參考)
前面一篇講了pointer,這篇要講只有C++才有的reference,
C是沒有reference的,相較於pointer,reference顯得平易近人多了!
reference有個很大的特性,它的意思是
別名(alias)的意思!
reference不像pointer記錄著變數的記憶體位置,它只是變數的
別名!
下面用個簡單的例子講解:
int iValue = 2;
int &iReference = iValue;
cout << iReference << endl; //會印出2
cout << &iReference << endl; //會印出iValue 的記憶體位置
cout << &iValue << endl; //會印出iValue本身自己的記憶體位置
上面的範例宣告了一個整數變數(iValue),和一個參考變數(iReference) 第一行會先印出2,
因為前面說過參考只是別名, 意思就是說iReference是iValue的別名,
在白話一點iReference等於iValue,
所以第二行會印出iReference(也就是iValue)的記憶體位置,假設印出0x28ff44(每台電腦都不一定是這個值)
第三行就是印出iValue自己的記憶體位置,所以!!!它也會印出0x28ff44!! 跟第二行一樣!! (因為他們兩個相等咩)
reference跟pointer不一樣的還有幾點,
reference一定要有初始值!!!
取值不需要加上*!!
不過其實參考使用的時機大部分是用在函數時, 因為是別名,所以可以避免複製大量的變數到函數去(就算是pointer函數,也會複製)
下面是一個簡單的參考函數範例:
void fnReference(int &iValue){
iValue = iValue +1;
cout << iValue << endl;
}
main(){
int iValue = 2;
fnReference(iValue);
cout << iValue << endl;
system("pause");
return 0;
}
在上面的範例我們宣告了一個函數(fnReference),其傳遞參數為參考型態(&iValue)
在主程式中(main),傳遞了單純的整數變數進去,
跟pointer不一樣,pointer是傳記憶體位置進去,
參考就直接傳普通的變數進去,
我們在函數中把傳遞進去的參數+1,然後印出,會印出3,
回到主程式以後,在印出iValue,一樣會印出3。
因為我們是傳遞參考,這就是call by reference!
最後,reference還有一個跟pointer不一樣的點!
就是reference不能用來進行運算!!!!!
學C/C++,我想pointer(指標)是最大的門檻吧!
這也是大部分人學C/C++,最痛的東西吧!
這篇就稍微的講解pointer!
pointer是專門用來儲存
某變數的
記憶體位置!
每宣告一個pointer時,就會配置一塊
4 bytes的記憶體空間,
專門用來儲存某變數的記憶體位置。
下面用簡單的code來說明,
int iValue = 10;
int *iPointer = &iValue;
printf("iPointer的value=%d \r\n" , *iPointer); //取值要用*
printf("iPointer儲存value的address=%X \r\n" , iPointer); //沒有*就是印出本身儲存的記憶體位置
printf("iPointer本身的address=%X \r\n" , &iPointer); //取得記憶體位置都是用&
printf("iValue 本身的address=%X \r\n" , &iValue); //取得記憶體位置都是用&
printf("iPointer的size=%d \r\n" , sizeof(iPointer));
printf("iValue的size=%d \r\n" , sizeof(iValue));
下面為執行結果以及說明,:
output | 說明 |
iPointer的value=10 | 印出儲存的記憶體位置本身的value,前面說過pointer是用來儲存記憶體位置, 如果要取得該記憶體位置的value,就是利用* |
iPointer儲存value的address=28FF3C | 印出iPointer儲存的資訊(記憶體位置) |
iPointer本身的address=28FF38 | iPointer自己的記憶體起始位置在哪 |
iValue 本身的address=28FF3C | 第四行就是印出iValue本身的記憶體起始位置,會發現跟第二行一樣,因為iPointer就是儲存這個資訊 |
iPointer的size=4 | 印出iPointer的大小,前面說過,每個pointer的大小都為4 bytes,不論型態為和 |
iValue的size=4 | 印出iValue本身的大小,因為是interger,所以為4 bytes |
上面為基本用法。
pointer也很常用來做字串的處理。
原因是用指標處理字串較省記憶體空間,也比較彈性,
我們可以宣告一個字串指標指向一個字串常數,
下面是個簡單的範例:
char *pValue[2] = {"Ken","Yang"};
char szValue[2][10] = {"Ken","Yang"};
printf("szValue的value=%s \r\n" , szValue[0]);
printf("pValue的value=%s \r\n" , pValue[0]);
printf("szValue的size=%d \r\n" , sizeof(szValue));
printf("pValue的size=%d \r\n" , sizeof(pValue));
下面為執行結果以及說明,顏色相同的為該對應的結果及說明:
output | 說明 |
szValue的value=Ken | 印出儲存在陣列0的value |
pValue的value=Ken | 印出儲存在指標陣列0的value |
szValue的size=20 | 字元陣列的大小為20 |
pValue的size=8 | 指標陣列的大小為8 |
可以發現陣列以及指標陣列的第0項,都是ken阿,可是大小卻都不一樣!
陣列的大小為20,而指標陣列為8
這就是為什麼使用指標會較為省空間的原因,且也較為彈性
因為字串指標是可以更改值的,可是字元陣列是不行的。
指標還有個特性,就是可以用來做運算,
可以看下面簡單的範例,
char *pString = "Ken";
cout << pString << endl;
cout << *(pString+1) << endl;
cout << sizeof(pString) << endl;
cout << sizeof(*(pString+1)) << endl;
cout << &pString << endl;
上面的例子,第一行我們先宣告字串指標,然後指定一個字串常數給他,
第二行就是印出value來(會印出Ken)
第三行就是進行指標的運算(會印出e,如果我們改成+2,就變成n)
第四行是印出大小,會印出4,因為說過指標的長度都固定為4
第五行也是印出大小,差別是印出該位置的字元大小,那就一定是1了
第六行就是印出該記憶體位置了,會發現字串指標跟前面講的變數指標(int, double..之類的)存取value或者存取記憶體的方式都不太同。
最後要講的是指標函數,用個簡單的範例來說明,
void fnPointer(int *pValue){
*pValue=*pValue+1;
cout << pValue << endl; //印出記憶體位置
}
main(){
int iValue = 2;
cout << &iValue << endl;
fnPointer(&iValue); //傳遞int變數的記憶體位置進去
cout << iValue << endl;
}
我們先宣告一個函數,那個函數裡的參數是pointer型態,
那麼使用方式就是傳遞某變數的記憶體位置進去即可,
因為我們說過指標是用來存某變數的記憶體位置!!!
所以就是傳遞記憶體位置進去。
然後我們再函數fnPointer裡面對value進行+1的動作,
然後在印出傳遞進來pointer的記憶體位置,
而主程式則是先印出iValue的記憶體位置,
在印出iValue的值。
會發現,主程式跟函數印出來的記憶體位置都相同!!
且在函數裡面進行+1以後,最後在main印出的value會變成3。
如果有些人可能會認為還是印出2,代表對pointer的概念還是不太了解(囧),因為是pointer,還是存取到原本的變數啊!
所以也是對原本的變數做操作!!!
印出2的方式我們稱為call by value,
但印出3的方式我們稱為call by address!
還有一種是call by reference!
後面一篇會講道!
以上是pointer一些簡單的介紹!
下一篇會介紹c++才有的參考(reference)