多線程,一個讓我學(xué)生時代感覺逼格較高的詞語之一执庐,因為聽不懂酪耕。當(dāng)時聽java多線程這部分課程時,已忘記我在干嘛轨淌,反正沒聽課迂烁。只記得有次在機(jī)房上機(jī)看尼,一男同學(xué)好像在看電視劇《老公的春天》,還被老師逮住了盟步,哈哈哈藏斩。俗話說“躲得過初一,躲不過十五”却盘,欠下的終歸要還的......

線程&多線程
線程的意義狰域,在上篇中就有提到,它作為操作系統(tǒng)調(diào)度的最小單元谷炸,多個線程能一塊執(zhí)行,提升性能禀挫,尤其在多處理器中旬陡,就不再多說了。
線程的創(chuàng)建與啟動
線程的啟動基本有三種方式:①繼承Thread语婴,重寫run()方法 ②實現(xiàn)Runnable接口描孟,重寫run()方法 ③創(chuàng)建FutureTask對象,創(chuàng)建Callable子類對象砰左,重寫call()方法匿醒。這篇先介紹下前兩種,因為它兩運(yùn)行完run()完沒有返回值缠导,而第三種是有返回值的:
繼承Thread
public class Test1 extends Thread {
@Override
public void run() {
for(int i = 0; i < 10; i++){
System.out.println("當(dāng)前線程名為:"+Thread.currentThread().getName() + "***哈哈哈***:" + i);
}
}
public static void main(String[] args) {
Test1 thread1 = new Test1();
thread1.start();
}
}
執(zhí)行結(jié)果如下:
這是一個最簡單的線程使用廉羔,只創(chuàng)建了一個線程對象,還是單線程僻造,再創(chuàng)建一個thread2憋他,就是多線程了。修改上面的的main函數(shù):
public static void main(String[] args) {
Test1 thread1 = new Test1();
Test1 thread2 = new Test1();
thread1.start();
thread2.start();
}
結(jié)果如下:
啟動線程的方式就是執(zhí)行Thread的start()方法髓削,strat()方法是一個native方法竹挡,它將啟動一個新線程,并執(zhí)行run()方法,可以瞅瞅它的實現(xiàn):
public synchronized void start() {
if (threadStatus != 0)
throw new IllegalThreadStateException();
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
private native void start0();
如果一個線程對象執(zhí)行run()方法立膛,不執(zhí)行start()方法揪罕,結(jié)果是怎樣的?繼續(xù)拿第一個單線程來試驗:
public static void main(String[] args) {
Test1 thread1 = new Test1();
thread1.run();
}
結(jié)果和thread.start()一模一樣宝泵,因為Thread也是Runnable的實現(xiàn)類好啰。
那么如果一個線程對象多次調(diào)用start()方法和run()方法的情況是怎樣的?來儿奶,接著試:
public static void main(String[] args) {
Test1 thread1 = new Test1();
thread1.start();
thread1.start();
}
結(jié)果報錯:
在Thread的start()方法處打斷點坎怪,可以看到thread1對象第一次執(zhí)行start()方法時,threadStatus=0廓握,成功執(zhí)行搅窿;當(dāng)thread1第二次執(zhí)行start()方法時嘁酿,threadStatus=2(這個狀態(tài)值并不是固定的,但都非零)男应,拋出了異常闹司,說明了同一個線程對象不能多次執(zhí)行start()方法。
接著咱們看一個線程對象多次執(zhí)行run()方法:
public static void main(String[] args) {
Test1 thread1 = new Test1();
thread1.run();
thread1.run();
}
執(zhí)行結(jié)果:
可以看到沐飘,這時候并沒有開啟新的線程游桩,main線程直接調(diào)用執(zhí)行了run()方法中代碼。所以耐朴,start()會開啟新的線程并在新線程中執(zhí)行run()方法借卧,而run()方法不會開啟新線程。
實現(xiàn)Runnable接口
public class Test2 implements Runnable {
@Override
public void run() {
for(int i =0; i < 10; i++){
System.out.println("當(dāng)前線程名為:"+Thread.currentThread().getName() + "***哈哈哈***:" + i);
}
}
public static void main(String[] args) {
Test2 test2 = new Test2();
Thread thread1 = new Thread(test2);
thread1.start();
}
}
執(zhí)行結(jié)果:
這個也是單線程筛峭,為了啟動線程铐刘,先創(chuàng)建一個Thread實例,再將Test2實例傳入影晓,在Thread所實現(xiàn)的run()方法處打斷點镰吵,可以看見Thread的run()方法就會調(diào)用target.run()。
小結(jié)
此篇主要介紹了兩種無返回結(jié)果的線程創(chuàng)建方式挂签。兩種方式的區(qū)別如下:①繼承Thread這種不是很靈活疤祭,因Java的單一繼承性,繼承了Thread就別再妄想繼承別的類了;②實現(xiàn)Runnable接口這種方式就巧妙地避開了這個弊端,更加符合面向?qū)ο蟮木幊谭绞狡狭#步档土司€程對象和線程任務(wù)的耦合性域蜗。總之,建議使用第二種實現(xiàn)Runnable的方式來創(chuàng)建線程。