日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java多线程(1)

發(fā)布時間:2024/1/17 java 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java多线程(1) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

3、具體內(nèi)容

???????? 從多線程開始,Java正式進入到應(yīng)用部分,而對于多線程的開發(fā),從Java EE上表現(xiàn)的并不是特別多,但是在Android開發(fā)之中使用較多,并且需要提醒的是,筆試或面試的過程之中,多線程所問到的問題是最多的。

3.1、多線程的基本概念

???????? 如果要想解釋多線程,那么首先應(yīng)該從單進程開始講起,最早的DOS系統(tǒng)有一個最大的特征:一旦電腦出現(xiàn)了病毒,電腦會立刻死機,因為傳統(tǒng)DOS系統(tǒng)屬于單進程的處理方式,即:在同一個時間段上只能有一個程序執(zhí)行。后來到了windows時代,電腦即使(非致命)存在了病毒,那么也可以正常使用,只是慢一些而已,因為windows屬于多進程的處理操作,但是這個 時候的資源依然只有一塊,所以在同一個時間段上會有多個程序共同執(zhí)行,而在一個時間點上只能有一個程序在執(zhí)行,多線程是在一個進程基礎(chǔ)之上的進一步劃分, 因為進程的啟動所消耗的時間是非常長的,所以在進程之上的進一步的劃分就變得非常重要,而且性能也會有所提高。

?

???????? 所有的線程一定要依附于進程才能夠存在,那么進程一旦消失了,線程也一定會消失,但是反過來不一定。而Java是為數(shù)不多的支持多線程的開發(fā)語言之一。

3.2、多線程的實現(xiàn)(重點)

???????? 在Java之中,如果要想實現(xiàn)多線程的程序,那么就必須依靠一個線程的主體類(就好比主類的概念一樣,表示的是一個線程的主類),但是這個線程的主體類在定義的時候也需要有一些特殊的要求,這個類可以繼承Thread類或?qū)崿F(xiàn)Runnable接口來完成定義。

3.2.1 、繼承Thread類實現(xiàn)多線程

???????? java.lang.Thread是一個負(fù)責(zé)線程操作的類,任何的類只需要繼承了Thread類就可以成為一個線程的主類,但是既然是主類必須有它的使用方法,而線程啟動的主方法是需要覆寫Thread類中的run()方法才可以。

范例:定義一個線程的主體類

class MyThread extends Thread { // 線程的主體類

??? private String title;

??? public MyThread(String title) {

??????? this.title = title;

??? }

??? @Override

??? public void run() { // 線程的主方法

??????? for (int x = 0; x < 50; x++) {

??????????? System.out.println(this.title + "運行,x = " + x);

??????? }

??? }

}

???????? 現(xiàn)在按照道理來講,已經(jīng)出現(xiàn)了線程類,并且里面也存在了相應(yīng)的操作方法,那么就應(yīng)該產(chǎn)生對象并調(diào)用里面的方法,自然下面編寫出了下的程序。

public class TestDemo {

??? public static void main(String[] args) throws Exception {

??????? MyThread mt1 = new MyThread("線程A") ;

??????? MyThread mt2 = new MyThread("線程B") ;

??????? MyThread mt3 = new MyThread("線程C") ;

??????? mt1.run() ;

??????? mt2.run() ;

??????? mt3.run() ;

??? }

}

???????? 但是以上的操作實話而言并沒有真正的啟動多線程,因為多個線程彼此之間的執(zhí)行一定是交替的方式運行,而此時是順序執(zhí)行,即:每一個對象的代碼執(zhí)行完之后才向下繼續(xù)執(zhí)行。如果要想在程序之中真正的啟動多線程,必須依靠Thread類的一個方法:public void start(),表示真正啟動多線程,調(diào)用此方法后會間接調(diào)用run()方法。

public class TestDemo {

??? public static void main(String[] args) throws Exception {

??????? MyThread mt1 = new MyThread("線程A") ;

??????? MyThread mt2 = new MyThread("線程B") ;

??????? MyThread mt3 = new MyThread("線程C") ;

??????? mt1.start() ;

??????? mt2.start() ;

??????? mt3.start() ;

??? }

}

???????? 此時可以發(fā)現(xiàn),多個線程之間彼此交替執(zhí)行,但是每次的執(zhí)行結(jié)果肯定是不一樣的。通過以上的代碼就可以得出結(jié)論:要想啟動線程必須依靠Thread類的start()方法執(zhí)行,線程啟動之后會默認(rèn)調(diào)用了run()方法。

疑問?為什么線程啟動的時候必須調(diào)用start()而不是直接調(diào)用run()?

???????? 發(fā)現(xiàn)調(diào)用了start()之后,實際上它執(zhí)行的還是覆寫后的run()方法,那為什么不直接調(diào)用run()方法呢?那么為了解釋此問題,下面打開Thread類的源代碼,觀察一下start()方法的定義。

??? 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();

???????? 打開此方法的實現(xiàn)代碼首先可以發(fā)現(xiàn)方法會拋出一個“IllegalThreadStateException”異常。按照之前所學(xué)習(xí)的方式來講,如果一個方法之中使用了throw拋出一個異常對象,那么這個異常應(yīng)該使用try…catch捕獲,或者是方法的聲明上使用throws拋出,但是這塊都沒有,因為這個異常類是屬于運行時異常(RuntimeException)的子類。

java.lang.Object

???????? |- java.lang.Throwable

?????????????????? |- java.lang.Exception

??????????????????????????? |- java.lang.RuntimeException

???????????????????????????????????? |- java.lang.IllegalArgumentException

?????????????????????????????????????????????? |- java.lang.IllegalThreadStateException

???????? 當(dāng)一個線程對象被重復(fù)啟動之后會拋出此異常,即:一個線程對象只能啟動唯一的一次。在start()方法之中有一個最為關(guān)鍵的部分就是start0()方法,而且這個方法上使用了一個native關(guān)鍵字的定義。

???????? native關(guān)鍵字指的是Java本地接口調(diào)用(Java Native Interface),即:是使用Java調(diào)用本機操作系統(tǒng)的函數(shù)功能完成一些特殊的操作,而這樣的代碼開發(fā)在Java之中幾乎很少出現(xiàn),因為Java的最大特點是可移植性,如果一個程序只能在固定的操作系統(tǒng)上使用,那么可移植性就將徹底的喪失,所以,此操作一般只作為興趣使用。

???????? 多線程的實現(xiàn)一定需要操作系統(tǒng)的支持,那么以上的start0()方法實際上就和抽象方法很類似沒有方法體,而這個方法體交給JVM去實現(xiàn),即:在windows下的JVM可能使用A方法實現(xiàn)了start0(),而在linux下的JVM可能使用了B方法實現(xiàn)了start0(),但是在調(diào)用的時候并不會去關(guān)心具體是何方式實現(xiàn)了start0()方法,只會關(guān)心最終的操作結(jié)果,交給JVM去匹配了不同的操作系統(tǒng)。

???????? 所以在多線程操作之中,使用start()方法啟動多線程的操作是需要進行操作系統(tǒng)函數(shù)調(diào)用的。

3.2.2 、實現(xiàn)Runnable接口實現(xiàn)多線程

???????? 使用Thread類的確是可以方便的進行多線程的實現(xiàn),但是這種方式最大的缺點就是單繼承的問題,為此,在java之中也可以利用Runnable接口來實現(xiàn)多線程,而這個接口的定義如下:

public interface Runnable {

??? public void run();

}

分享:如何區(qū)分新老接口?

???????? 在JDK之中,由于其發(fā)展的時間較長,那么會出現(xiàn)一些新的接口和老的接口,這兩者有一個最大的明顯特征:所有最早提供的接口方法里面都不加上public,所有的新接口里面都有public。

范例:通過Runnable接口實現(xiàn)多線程

class MyThread implements Runnable { // 線程的主體類

??? private String title;

??? public MyThread(String title) {

??????? this.title = title;

??? }

??? @Override

??? public void run() { // 線程的主方法

??????? for (int x = 0; x < 50; x++) {

??????????? System.out.println(this.title + "運行,x = " + x);

??????? }

??? }

}

???????? 這個時候和之前的繼承Thread類區(qū)別不大,但是唯一的好處就是避免了單繼承局限,不過現(xiàn)在問題也就來了。剛剛解釋過,如果要想啟動多線程依靠Thread類的start()方法完成,之前繼承Thread類的時候可以將此方法直接繼承過來使用,但現(xiàn)在實現(xiàn)的是Runable接口,沒有這個方法可以繼承了,為了解決這個問題,還是需要依靠Thread類完成,在Thread類中定義了一個構(gòu)造方法:public Thread(Runnable target),接收Runnable接口對象。

范例:利用Thread類啟動多線程

public class TestDemo {

??? public static void main(String[] args) throws Exception {

??????? MyThread mt1 = new MyThread("線程A");

??????? MyThread mt2 = new MyThread("線程B");

??????? MyThread mt3 = new MyThread("線程C");

??????? new Thread(mt1).start();

??????? new Thread(mt2).start();

??????? new Thread(mt3).start();

??? }

}

???????? 這個時候就實現(xiàn)了多線程的啟動,而且沒有了單繼承局限。

3.2.3 、Thread類和Runnable接口實現(xiàn)多線程的區(qū)別(面試題)

???????? 現(xiàn)在Thread類和Runnable接口都可以做為同一功能的方式來實現(xiàn)多線程,那么這兩者如果從Java的實際開發(fā)而言,肯定使用Runnable接口,因為可以有效的避免單繼承的局限,那么除了這些之外,這兩種方式是否還有其他聯(lián)系呢?

???????? 為了解釋這兩種方式的聯(lián)系,下面可以打開Thread類的定義:

public class Thread extends Object implements Runnable

???????? 發(fā)現(xiàn)Thread類也是Runnable接口的子類,而如果真的是這樣,那么之前程序的結(jié)構(gòu)就變?yōu)榱艘韵滦问健?/p>

?

???????? 這個時候所表現(xiàn)出來的代碼模式非常類似于代理設(shè)計模式,但是它并不是嚴(yán)格意義上代理設(shè)計模式,因為從嚴(yán)格來講代理設(shè)計模式之中,代理主題所能夠使用的方法依然是接口中定義的run()方法,而此處代理主題調(diào)用的是start()方法,所以只能夠說形式上類似于代理設(shè)計模式,但本質(zhì)上還是有差別的。

???????? 但是除了以上的聯(lián)系之外,對于Runnable和Thread類還有一個不太好區(qū)分的區(qū)別:使用Runnable接口可以更加方便的表示出數(shù)據(jù)共享的概念。

范例:通過繼承Thread類實現(xiàn)賣票程序

package cn.mldn.demo;

class MyThread extends Thread { // 線程的主體類

??? private int ticket = 5; // 一共5張票

??? @Override

??? public void run() { // 線程的主方法

??????? for (int x = 0; x < 50; x++) {

??????????? if (this.ticket > 0) {

??????????????? System.out.println("賣票,ticket = " + this.ticket --);

??????????? }

??????? }

??? }

}

public class TestDemo {

??? public static void main(String[] args) throws Exception {

??????? MyThread mt1 = new MyThread();

??????? MyThread mt2 = new MyThread();

??????? MyThread mt3 = new MyThread();

??????? mt1.start() ;

??????? mt2.start() ;

??????? mt3.start() ;

??? }

}

???????? 現(xiàn)在的結(jié)果是一共買出了15張票,等于是每一個線程對象各自賣各自的5張票,這個時候的內(nèi)存關(guān)系圖如下:

?

范例:利用Runnable來實現(xiàn)多線程

package cn.mldn.demo;

class MyThread implements Runnable { // 線程的主體類

??? private int ticket = 5; // 一共5張票

??? @Override

??? public void run() { // 線程的主方法

??????? for (int x = 0; x < 50; x++) {

??????????? if (this.ticket > 0) {

??????????????? System.out.println("賣票,ticket = " + this.ticket--);

??????????? }

??????? }

??? }

}

public class TestDemo {

??? public static void main(String[] args) throws Exception {

??????? MyThread mt = new MyThread();

??????? new Thread(mt).start();

??????? new Thread(mt).start();

??????? new Thread(mt).start();

??? }

}

??? 現(xiàn)在使用繼承Thread類也可以實現(xiàn)同樣的功能。

package cn.mldn.demo;

class MyThread extends Thread { // 線程的主體類

??? private int ticket = 5; // 一共5張票

??? @Override

??? public void run() { // 線程的主方法

??????? for (int x = 0; x < 50; x++) {

??????????? if (this.ticket > 0) {

??????????????? System.out.println("賣票,ticket = " + this.ticket--);

??????????? }

??????? }

??? }

}

public class TestDemo {

??? public static void main(String[] args) throws Exception {

??????? MyThread mt = new MyThread();

??????? new Thread(mt).start();

??????? new Thread(mt).start();

??????? new Thread(mt).start();

??? }

}

面試題:請解釋多線程的兩種實現(xiàn)方式及區(qū)別?分別編寫程序以驗證兩種實現(xiàn)方式。

???????? · 多線程的兩種實現(xiàn)方式都需要一個線程的主類,而這個類可以實現(xiàn)Runnable接口或繼承Thread類,不管使用何種方式都必須在子類之中覆寫run()方法,此方法為線程的主方法;

???????? · Thread類是Runnable接口的子類,而且使用Runnable接口可以避免單繼承局限,以及更加方便的實現(xiàn)數(shù)據(jù)共享的概念。

轉(zhuǎn)載于:https://www.cnblogs.com/guwenren/archive/2013/04/10/3013203.html

總結(jié)

以上是生活随笔為你收集整理的Java多线程(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。