學習java多線程的一下知識的總結(jié),寫在這里揖膜,防止自己遺忘誓沸,也是為了復習。
JVM的啟動是單線程還是多線程的壹粟?蔽介?
JVM啟動的時候不僅僅啟動了主線程,而且啟動了垃圾回收線程煮寡,所以JVM的啟動是多線程的虹蓄。
如何實現(xiàn)多線程?
兩種方式:
- 繼承Thread類
- 自定義MyThread類繼承了Thread類
- 重寫MyThread類中的run()方法
- 創(chuàng)建MyThread對象
- 啟動線程對象
- 實現(xiàn)Runable接口
- 自定義MyRunnable類實現(xiàn)了Runnable接口
- 重寫MyRunnable類中的run()方法
- 創(chuàng)建MyRunnable對象
- 創(chuàng)建Thread對象幸撕,把MyRunnable對象對象作為構(gòu)造函數(shù)的入?yún)?/li>
對于繼承Thread來說薇组,是通過重寫了run
方法來實現(xiàn)的,因為一個類的代碼并不是都需要多線程執(zhí)行的坐儿,只會執(zhí)行run
方法里面的代碼律胀。
為什么有兩張方式來實現(xiàn)多線程宋光??炭菌?
- 由于Java只支持單繼承罪佳,避免單繼承導致的多線程的局限性
- 適合多個相同程序的代碼去處理同一個資源,吧線程相同程序的代碼黑低,數(shù)據(jù)有效分離赘艳,體現(xiàn)了Java面向?qū)ο蟮脑O計思想。
如果重復調(diào)用run
會發(fā)現(xiàn)克握,還是單線程執(zhí)行蕾管,原因是run
方法它是單行程的。
可以通過start
方法來執(zhí)行菩暗,如果調(diào)用兩次start
方法掰曾,并不能進行多線程操作,由于已經(jīng)執(zhí)行了start
方法停团,再次執(zhí)行start
會報錯,旷坦,報錯信息如下:
所以可以實例化兩個對象,分別啟動對象的線程佑稠,會發(fā)現(xiàn)他們兩個確實是多線程執(zhí)行的塞蹭。看到兩個for循環(huán)是同時執(zhí)行的讶坯,并沒有順序執(zhí)行番电。
代碼示例:
package com.aircjm.thread;
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}
}
package com.aircjm.thread;
public class ThreadTest {
public static void main(String[] args) {
MyThread myThread = new MyThread();
//由于run()方法時單線程的,所以還是按照單線程執(zhí)行辆琅,一個run()執(zhí)行完了漱办,另一個run()才會執(zhí)行
//myThread.run();
//myThread.run();
//可以通過start()方法來啟動線程
//兩者之間的區(qū)別,start是使該線程開始執(zhí)行婉烟,JVM調(diào)用該線程的run()方法
//myThread.start();
//myThread.start();
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
myThread1.start();
myThread2.start();
}
}
如何獲取繼承Thread的線程對象的名稱
public final String getName() //獲取線程的名詞
線程控制的幾個方法:
休眠線程:
public static void sleep(long millis) throws InterruptedException
在指定的毫秒數(shù)內(nèi)讓當前正在執(zhí)行的線程休眠(暫停執(zhí)行)娩井,此操作受到系統(tǒng)計時器和調(diào)度程序精度和準確性的影響。該線程不丟失任何監(jiān)視器的所屬權(quán)似袁。
啟動線程:
start
public void start()
使該線程開始執(zhí)行洞辣;Java 虛擬機調(diào)用該線程的 run 方法。
結(jié)果是兩個線程并發(fā)地運行昙衅;當前線程(從調(diào)用返回給 start 方法)和另一個線程(執(zhí)行其 run 方法)扬霜。
多次啟動一個線程是非法的。特別是當線程已經(jīng)結(jié)束執(zhí)行后而涉,不能再重新啟動著瓶。
拋出:
IllegalThreadStateException - 如果線程已經(jīng)啟動。
另請參見:
run(), stop()
run
public void run()
如果該線程是使用獨立的 Runnable 運行對象構(gòu)造的啼县,則調(diào)用該 Runnable 對象的 run 方法材原;否則沸久,該方法不執(zhí)行任何操作并返回。
Thread 的子類應該重寫該方法余蟹。
加入線程:
禮讓線程:
守護線程:
中斷線程:
啟動線程用的是哪個方法卷胯?
start()
run()和start()方法的區(qū)別?
- run直接調(diào)用威酒,調(diào)用的是普通方法
- start()方法窑睁,是啟動線程,然后JVM調(diào)用了run()方法
如何讓線程安全兼搏?卵慰?
給需要線程安全的地方進行加鎖
public class SellTicket implements Runnable {
private Integer ticketNum = 100;
public void run() {
while (true){
synchronized (ticketNum){
if (ticketNum>0){
System.out.println("now is sell "+ ticketNum-- +" ticket");
}
}
}
}
}
加鎖的方式有多種沙郭,可以給代碼塊加鎖(鎖對象是任意對象)佛呻,可以給方法加鎖(鎖對象是this),也可以給靜態(tài)方法加鎖(鎖對象是字節(jié)碼文件)
學習到的線程安全的對象有:
StringBuffer stringBuffer = new StringBuffer();
Vector<String> vector = new Vector<String>();
Hashtable<String, Object> hashTable = new Hashtable<String, Object>();
// 即使線程安全但是也不推薦使用
Vector<String> vector = new Vector<String>();
Hashtable<String, Object> hashTable = new Hashtable<String, Object>();
// 如何使用線程安全的List呢??
List<String> list = Collections.synchronizedList(new ArrayList<String>()); // 線程安全
List<String> list1 = new ArrayList<String>(); //線程不安全
通過靜態(tài)方法獲取到線程安全的List集合