學(xué)習(xí)java多線程的一下知識的總結(jié),寫在這里,防止自己遺忘,也是為了復(fù)習(xí)。
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只支持單繼承,避免單繼承導(dǎo)致的多線程的局限性
- 適合多個相同程序的代碼去處理同一個資源,吧線程相同程序的代碼,數(shù)據(jù)有效分離,體現(xiàn)了Java面向?qū)ο蟮脑O(shè)計思想。
如果重復(fù)調(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 的子類應(yīng)該重寫該方法。
加入線程:
禮讓線程:
守護線程:
中斷線程:
啟動線程用的是哪個方法?
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é)碼文件)
學(xué)習(xí)到的線程安全的對象有:
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集合