昨晚在看死鎖相關(guān)的東西,看到了synchronized關(guān)鍵字,然后就想寫(xiě)一篇關(guān)于synchronized關(guān)鍵字的博客,就去仔細(xì)看了看相關(guān)的東西。synchronized關(guān)鍵字在使用多線程的時(shí)候使用,于是復(fù)習(xí)一下多線程的東西,寫(xiě)篇博客加深一下印象。 java中實(shí)現(xiàn)多線程的方式有兩種,一是繼承Thread類(lèi),二是實(shí)現(xiàn)Runnable接口,先看繼承Thread類(lèi)。
Thread類(lèi) Thread是java.lang包中的一個(gè)類(lèi),實(shí)現(xiàn)了Runnable接口,Runnable接口源碼如下,簡(jiǎn)單粗暴。
ClassExtendsThread類(lèi),繼承了Thread類(lèi),在run方法中依次遞減打印出10到1。
main函數(shù)代碼如下:
運(yùn)行結(jié)果如下:
Thread-0--->10Thread-1--->10Thread-0--->9Thread-1--->9Thread-0--->8Thread-1--->8Thread-0--->7Thread-1--->7Thread-0--->6Thread-1--->6Thread-0--->5Thread-0--->4Thread-1--->5Thread-0--->3Thread-0--->2Thread-1--->4Thread-0--->1Thread-1--->3Thread-1--->2Thread-1--->1 從結(jié)果中可以看出,兩個(gè)線程都啟動(dòng)起來(lái),并且交叉運(yùn)行,但是這兩個(gè)線程可以認(rèn)為他們是不關(guān)聯(lián)的,因?yàn)榫€程1和線程2各自擁有了新的num變量,即這兩個(gè)線程不共享該變量。接下來(lái)看實(shí)現(xiàn)Runnable接口的多線程Demo。
Runnable接口上面已經(jīng)看了Runnable接口的源碼,直接上Demo。
public class ClassImplRunnable implements Runnable { private int num = 10; @Override public void run() { for (int i = 0; i < 10; i++) { if (num > 0) { // 因?yàn)镽unnable中沒(méi)有currentThread方法,所以要加上Thread System.out.println(Thread.currentThread().getName() + "--->" + num--); } } }} ClassImplRunnable和ClassExtendsThread代碼幾乎一樣,不同的是實(shí)現(xiàn)了Runnable接口。測(cè)試代碼如下:
這里的ClassImplRunnable只實(shí)現(xiàn)了Runnable接口,但是沒(méi)有start方法,無(wú)法啟動(dòng)線程,但是Thread類(lèi)中有個(gè)構(gòu)造方法:
傳入一個(gè)實(shí)現(xiàn)Runnable接口的類(lèi)即可創(chuàng)建一個(gè)新的線程,然后調(diào)用start方法即可啟動(dòng)線程。注意啟動(dòng)線程只能用start方法,如果調(diào)用run方法,那么就只是執(zhí)行了一個(gè)方法,并沒(méi)有啟動(dòng)線程。 運(yùn)行結(jié)果如下:
兩個(gè)線程交叉運(yùn)行,因?yàn)闆](méi)有使用同步鎖。同時(shí),這里兩個(gè)線程使用了同一個(gè)對(duì)象構(gòu)造了Thread,所以其實(shí)兩個(gè)線程運(yùn)行的時(shí)候共享了num變量。 仔細(xì)回顧一下兩次運(yùn)行,發(fā)現(xiàn)繼承Thread類(lèi)的ClassExtendsThread類(lèi)運(yùn)行時(shí),是直接創(chuàng)建了兩個(gè)ClassExtendsThread對(duì)象,但是ClassImplRunnable類(lèi)是創(chuàng)建了一個(gè)對(duì)象,但是創(chuàng)建了兩個(gè)Thread對(duì)象并啟動(dòng)線程,那么就不能說(shuō)繼承Thread的類(lèi)實(shí)現(xiàn)多線程不能共享資源,實(shí)現(xiàn)了Runnable接口的多線程才能共享資源。 接下里來(lái)模仿一下ClassImplRunnable類(lèi)啟動(dòng)線程的方式,代碼如下:
運(yùn)行結(jié)果如下:
Thread-2--->10Thread-1--->9Thread-1--->7Thread-1--->6Thread-1--->5Thread-1--->4Thread-1--->3Thread-1--->2Thread-1--->1Thread-2--->8 結(jié)果可以看出,其實(shí)是共享了資源(num)的。 這里線程名字變了,因?yàn)閚ew了一個(gè)ClassExtendsThread對(duì)象的時(shí)候,就已經(jīng)創(chuàng)建了一個(gè)線程,而后面調(diào)用Thread的構(gòu)造函數(shù)又創(chuàng)建了兩個(gè)線程,而且只啟動(dòng)了線程2和3,即Thread-1、Thread-2。 今天下午查了一下午資料,也沒(méi)有一個(gè)講的清楚的好文章,最后靈光一閃,用Google搜了一下,結(jié)果直接搜出來(lái)兩篇講的很好的文章,一個(gè)是GitHub的,一個(gè)是博客園的,按道理說(shuō)百度和必應(yīng)都能搜出來(lái)的,但是。。。
用Thread和Runnable都可以實(shí)現(xiàn)多線程,但是一般情況下還是用實(shí)現(xiàn)Runnable接口的方法來(lái)實(shí)現(xiàn)多線程,原因有以下幾點(diǎn): 1. 因?yàn)镴ava的單繼承特性,如果繼承Thread的話(huà)就不能再繼承其他類(lèi),而接口是可以實(shí)現(xiàn)多個(gè)的,所以實(shí)現(xiàn)Runnable接口更加靈活; 2. 關(guān)于很多文章提到的資源共享問(wèn)題,繼承了Thread類(lèi)的類(lèi)的對(duì)象,已經(jīng)是一個(gè)線程了,是可以直接調(diào)用start方法來(lái)啟動(dòng)線程的,但是如果要實(shí)現(xiàn)類(lèi)似于ClassImplRunnable這樣的所謂的“資源共享”,還需要把對(duì)象傳入Thread的構(gòu)造函數(shù)重新實(shí)例化Thread對(duì)象,比較麻煩,所以還是用實(shí)現(xiàn)Runnable接口的方法便捷一點(diǎn)。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注