導航:首頁 > 編程語言 > java線程怎麼用

java線程怎麼用

發布時間:2024-04-24 13:46:19

⑴ 在java 中多線程的實現方法有哪些,如何使用

Java多線程的創建及啟動

Java中線程的創建常見有如三種基本形式

1.繼承Thread類,重寫該類的run()方法。

復制代碼

1 class MyThread extends Thread {

2

3 private int i = 0;

4

5 @Override

6 public void run() {

7 for (i = 0; i < 100; i++) {

8 System.out.println(Thread.currentThread().getName() + " " + i);

9 }

10 }

11 }

復制代碼

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4 for (int i = 0; i < 100; i++) {

5 System.out.println(Thread.currentThread().getName() + " " + i);

6 if (i == 30) {

7 Thread myThread1 = new MyThread(); // 創建一個新的線程 myThread1 此線程進入新建狀態

8 Thread myThread2 = new MyThread(); // 創建一個新的線程 myThread2 此線程進入新建狀態

9 myThread1.start(); // 調用start()方法使得線程進入就緒狀態

10 myThread2.start(); // 調用start()方法使得線程進入就緒狀態

11 }

12 }

13 }

14 }

復制代碼

如上所示,繼承Thread類,通過重寫run()方法定義了一個新的線程類MyThread,其中run()方法的方法體代表了線程需要完成的任務,稱之為線程執行體。當創建此線程類對象時一個新的線程得以創建,並進入到線程新建狀態。通過調用線程對象引用的start()方法,使得該線程進入到就緒狀態,此時此線程並不一定會馬上得以執行,這取決於CPU調度時機。

2.實現Runnable介面,並重寫該介面的run()方法,該run()方法同樣是線程執行體,創建Runnable實現類的實例,並以此實例作為Thread類的target來創建Thread對象,該Thread對象才是真正的線程對象。

復制代碼

1 class MyRunnable implements Runnable {

2 private int i = 0;

3

4 @Override

5 public void run() {

6 for (i = 0; i < 100; i++) {

7 System.out.println(Thread.currentThread().getName() + " " + i);

8 }

9 }

10 }

復制代碼

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4 for (int i = 0; i < 100; i++) {

5 System.out.println(Thread.currentThread().getName() + " " + i);

6 if (i == 30) {

7 Runnable myRunnable = new MyRunnable(); // 創建一個Runnable實現類的對象

8 Thread thread1 = new Thread(myRunnable); // 將myRunnable作為Thread target創建新的線程

9 Thread thread2 = new Thread(myRunnable);

10 thread1.start(); // 調用start()方法使得線程進入就緒狀態

11 thread2.start();

12 }

13 }

14 }

15 }

復制代碼

相信以上兩種創建新線程的方式大家都很熟悉了,那麼Thread和Runnable之間到底是什麼關系呢?我們首先來看一下下面這個例子。

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4 for (int i = 0; i < 100; i++) {

5 System.out.println(Thread.currentThread().getName() + " " + i);

6 if (i == 30) {

7 Runnable myRunnable = new MyRunnable();

8 Thread thread = new MyThread(myRunnable);

9 thread.start();

10 }

11 }

12 }

13 }

14

15 class MyRunnable implements Runnable {

16 private int i = 0;

17

18 @Override

19 public void run() {

20 System.out.println("in MyRunnable run");

21 for (i = 0; i < 100; i++) {

22 System.out.println(Thread.currentThread().getName() + " " + i);

23 }

24 }

25 }

26

27 class MyThread extends Thread {

28

29 private int i = 0;

30

31 public MyThread(Runnable runnable){

32 super(runnable);

33 }

34

35 @Override

36 public void run() {

37 System.out.println("in MyThread run");

38 for (i = 0; i < 100; i++) {

39 System.out.println(Thread.currentThread().getName() + " " + i);

40 }

41 }

42 }

復制代碼

同樣的,與實現Runnable介面創建線程方式相似,不同的地方在於

1 Thread thread = new MyThread(myRunnable);

那麼這種方式可以順利創建出一個新的線程么?答案是肯定的。至於此時的線程執行體到底是MyRunnable介面中的run()方法還是MyThread類中的run()方法呢?通過輸出我們知道線程執行體是MyThread類中的run()方法。其實原因很簡單,因為Thread類本身也是實現了Runnable介面,而run()方法最先是在Runnable介面中定義的方法。

1 public interface Runnable {

2

3 public abstract void run();

4

5 }

我們看一下Thread類中對Runnable介面中run()方法的實現:

復制代碼

@Override

public void run() {

if (target != null) {

target.run();

}

}

復制代碼

也就是說,當執行到Thread類中的run()方法時,會首先判斷target是否存在,存在則執行target中的run()方法,也就是實現了Runnable介面並重寫了run()方法的類中的run()方法。但是上述給到的列子中,由於多態的存在,根本就沒有執行到Thread類中的run()方法,而是直接先執行了運行時類型即MyThread類中的run()方法。

3.使用Callable和Future介面創建線程。具體是創建Callable介面的實現類,並實現clall()方法。並使用FutureTask類來包裝Callable實現類的對象,且以此FutureTask對象作為Thread對象的target來創建線程。

看著好像有點復雜,直接來看一個例子就清晰了。

復制代碼

1 public class ThreadTest {

2

3 public static void main(String[] args) {

4

5 Callable<Integer> myCallable = new MyCallable(); // 創建MyCallable對象

6 FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask來包裝MyCallable對象

7

8 for (int i = 0; i < 100; i++) {

9 System.out.println(Thread.currentThread().getName() + " " + i);

10 if (i == 30) {

11 Thread thread = new Thread(ft); //FutureTask對象作為Thread對象的target創建新的線程

12 thread.start(); //線程進入到就緒狀態

13 }

14 }

15

16 System.out.println("主線程for循環執行完畢..");

17

18 try {

19 int sum = ft.get(); //取得新創建的新線程中的call()方法返回的結果

20 System.out.println("sum = " + sum);

21 } catch (InterruptedException e) {

22 e.printStackTrace();

23 } catch (ExecutionException e) {

24 e.printStackTrace();

25 }

26

27 }

28 }

29

30

31 class MyCallable implements Callable<Integer> {

32 private int i = 0;

33

34 // 與run()方法不同的是,call()方法具有返回值

35 @Override

36 public Integer call() {

37 int sum = 0;

38 for (; i < 100; i++) {

39 System.out.println(Thread.currentThread().getName() + " " + i);

40 sum += i;

41 }

42 return sum;

43 }

44

45 }

復制代碼

首先,我們發現,在實現Callable介面中,此時不再是run()方法了,而是call()方法,此call()方法作為線程執行體,同時還具有返回值!在創建新的線程時,是通過FutureTask來包裝MyCallable對象,同時作為了Thread對象的target。那麼看下FutureTask類的定義:

1 public class FutureTask<V> implements RunnableFuture<V> {

2

3 //....

4

5 }

1 public interface RunnableFuture<V> extends Runnable, Future<V> {

2

3 void run();

4

5 }

於是,我們發現FutureTask類實際上是同時實現了Runnable和Future介面,由此才使得其具有Future和Runnable雙重特性。通過Runnable特性,可以作為Thread對象的target,而Future特性,使得其可以取得新創建線程中的call()方法的返回值。

執行下此程序,我們發現sum = 4950永遠都是最後輸出的。而「主線程for循環執行完畢..」則很可能是在子線程循環中間輸出。由CPU的線程調度機制,我們知道,「主線程for循環執行完畢..」的輸出時機是沒有任何問題的,那麼為什麼sum =4950會永遠最後輸出呢?

原因在於通過ft.get()方法獲取子線程call()方法的返回值時,當子線程此方法還未執行完畢,ft.get()方法會一直阻塞,直到call()方法執行完畢才能取到返回值。

上述主要講解了三種常見的線程創建方式,對於線程的啟動而言,都是調用線程對象的start()方法,需要特別注意的是:不能對同一線程對象兩次調用start()方法。

你好,本題已解答,如果滿意

請點右下角「採納答案」。


⑵ 如何創建並運行Java線程

Java線程類也是一個object類,它的實例都繼承自java.lang.Thread或其子類。 可以用如下方式用java中創建一個線程:

Tread thread = new Thread();

執行該線程可以調用該線程的start()方法:

thread.start();

在上面的例子中,我們並沒有為線程編寫運行代碼,因此調用該方法後線程就終止了。

編寫線程運行時執行的代碼有兩種方式:一種是創建Thread子類的一個實例並重寫run方法,第二種是創建類的時候實現Runnable介面。接下來我們會具體講解這兩種方法:

創建Thread的子類

創建Thread子類的一個實例並重寫run方法,run方法會在調用start()方法之後被執行。例子如下:

public class MyThread extends Thread {
public void run(){
System.out.println("MyThread running");
}
}

可以用如下方式創建並運行上述Thread子類

MyThread myThread = new MyThread();
myTread.start();

一旦線程啟動後start方法就會立即返回,而不會等待到run方法執行完畢才返回。就好像run方法是在另外一個cpu上執行一樣。當run方法執行後,將會列印出字元串MyThread running。

你也可以如下創建一個Thread的匿名子類:

Thread thread = new Thread(){
public void run(){
System.out.println("Thread Running");
}
};
thread.start();

當新的線程的run方法執行以後,計算機將會列印出字元串」Thread Running」。

實現Runnable介面

第二種編寫線程執行代碼的方式是新建一個實現了java.lang.Runnable介面的類的實例,實例中的方法可以被線程調用。下面給出例子:

public class MyRunnable implements Runnable {
public void run(){
System.out.println("MyRunnable running");
}
}

為了使線程能夠執行run()方法,需要在Thread類的構造函數中傳入 MyRunnable的實例對象。示例如下:

Thread thread = new Thread(new MyRunnable());
thread.start();

當線程運行時,它將會調用實現了Runnable介面的run方法。上例中將會列印出」MyRunnable running」。

同樣,也可以創建一個實現了Runnable介面的匿名類,如下所示:

Runnable myRunnable = new Runnable(){
public void run(){
System.out.println("Runnable running");
}
}
Thread thread = new Thread(myRunnable);
thread.start();

創建子類還是實現Runnable介面?

對於這兩種方式哪種好並沒有一個確定的答案,它們都能滿足要求。就我個人意見,我更傾向於實現Runnable介面這種方法。因為線程池可以有效的管理實現了Runnable介面的線程,如果線程池滿了,新的線程就會排隊等候執行,直到線程池空閑出來為止。而如果線程是通過實現Thread子類實現的,這將會復雜一些。

有時我們要同時融合實現Runnable介面和Thread子類兩種方式。例如,實現了Thread子類的實例可以執行多個實現了Runnable介面的線程。一個典型的應用就是線程池。

常見錯誤:調用run()方法而非start()方法

創建並運行一個線程所犯的常見錯誤是調用線程的run()方法而非start()方法,如下所示:

Thread newThread = new Thread(MyRunnable());
newThread.run(); //should be start();

起初你並不會感覺到有什麼不妥,因為run()方法的確如你所願的被調用了。但是,事實上,run()方法並非是由剛創建的新線程所執行的,而是被創建新線程的當前線程所執行了。也就是被執行上面兩行代碼的線程所執行的。想要讓創建的新線程執行run()方法,必須調用新線程的start方法。

線程名

當創建一個線程的時候,可以給線程起一個名字。它有助於我們區分不同的線程。例如:如果有多個線程寫入System.out,我們就能夠通過線程名容易的找出是哪個線程正在輸出。例子如下:

MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable, "New Thread");
thread.start();
System.out.println(thread.getName());

需要注意的是,因為MyRunnable並非Thread的子類,所以MyRunnable類並沒有getName()方法。可以通過以下方式得到當前線程的引用:

Thread.currentThread();

因此,通過如下代碼可以得到當前線程的名字:

String threadName = Thread.currentThread().getName();

線程代碼舉例:

這里是一個小小的例子。首先輸出執行main()方法線程名字。這個線程JVM分配的。然後開啟10個線程,命名為1~10。每個線程輸出自己的名字後就退出。

public class ThreadExample {
public static void main(String[] args){
System.out.println(Thread.currentThread().getName());
for(int i=0; i<10; i++){
new Thread("" + i){
public void run(){
System.out.println("Thread: " + getName() + "running");
}
}.start();
}
}
}

需要注意的是,盡管啟動線程的順序是有序的,但是執行的順序並非是有序的。也就是說,1號線程並不一定是第一個將自己名字輸出到控制台的線程。這是因為線程是並行執行而非順序的。Jvm和操作系統一起決定了線程的執行順序,他和線程的啟動順序並非一定是一致的。

⑶ java怎麼實現線程

Thread類本質上是實現了Runnable介面的一個實例,代表一個線程的實例。啟動線程的唯一方法就是通過Thread類的start()實例方法。start()方法是一個native方法,它將啟動一個新線程,並執行run()方法。這種方式實現多線程很簡單,通過自己的類直接extend Thread,並復寫run()方法,就可以啟動新線程並執行自己定義的run()方法。

如果自己的類已經extends另一個類,就無法直接extends Thread,此時,可以實現一個Runnable介面。

ExecutorService、Callable、Future三個介面實際上都是屬於Executor框架。返回結果的線程是在JDK1.5中引入的新特徵,有了這種特徵就不需要再為了得到返回值而大費周折了。而且自己實現了也可能漏洞百出。

可返回值的任務必須實現Callable介面。類似的,無返回值的任務必須實現Runnable介面。

執行Callable任務後,可以獲取一個Future的對象,在該對象上調用get就可以獲取到Callable任務返回的Object了。

注意:get方法是阻塞的,即:線程無返回結果,get方法會一直等待。

再結合線程池介面ExecutorService就可以實現傳說中有返回結果的多線程了。

⑷ java線程池(一) 簡述線程池的幾種使用方式

首先說明下java線程是如何實現線程重用的
1. 線程執行完一個Runnable的run()方法後,不會被殺死
2. 當線程被重用時,這個線程會進入新Runnable對象的run()方法12

java線程池由Executors提供的幾種靜態方法創建線程池。下面通過代碼片段簡單介紹下線程池的幾種實現方式。後續會針對每個實現方式做詳細的說明
newFixedThreadPool
創建一個固定大小的線程池
添加的任務達到線程池的容量之後開始加入任務隊列開始線程重用總共開啟線程個數跟指定容量相同。
@Test
public void newFixedThreadPool() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService = Executors.newFixedThreadPool(1, new ThreadFactoryBuilder().build());
RunThread run1 = new RunThread("run 1");
executorService.execute(run1);
executorService.shutdown();
}12345678

newSingleThreadExecutor
僅支持單線程順序處理任務
@Test
public void newSingleThreadExecutor() throws Exception {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();

}123456789

newCachedThreadPool
這種情況跟第一種的方式類似,不同的是這種情況線程池容量上線是Integer.MAX_VALUE 並且線程池開啟緩存60s
@Test
public void newCachedThreadPool() throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService = Executors.newCachedThreadPool(new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();

}123456789

newWorkStealingPool
支持給定的並行級別,並且可以使用多個隊列來減少爭用。
@Test
public void newWorkStealingPool() throws Exception {
ExecutorService executorService = Executors.newWorkStealingPool();
executorService = Executors.newWorkStealingPool(1);
RunThread run1 = new RunThread("run 1");
executorService.execute(run1);
executorService.shutdown();

}123456789

newScheledThreadPool
看到的現象和第一種相同,也是在線程池滿之前是新建線程,然後開始進入任務隊列,進行線程重用
支持定時周期執行任務(還沒有看完)
@Test
public void newScheledThreadPool() throws Exception {
ExecutorService executorService = Executors.newScheledThreadPool(1);
executorService = Executors.newScheledThreadPool(1, new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();

}

⑸ 在Java 中多線程的實現方法有哪些,如何使用~~~~~~~~~~~~~~~~~~急

1、 認識Thread和Runnable

Java中實現多線程有兩種途徑:繼承Thread類或者實現Runnable介面。Runnable是介面,建議用介面的方式生成線程,因為介面可以實現多繼承,況且Runnable只有一個run方法,很適合繼承。在使用Thread的時候只需繼承Thread,並且new一個實例出來,調用start()方法即可以啟動一個線程。

Thread Test = new Thread();

Test.start();

在使用Runnable的時候需要先new一個實現Runnable的實例,之後啟動Thread即可。

Test impelements Runnable;

Test t = new Test();

Thread test = new Thread(t);

test.start();

總結:Thread和Runnable是實現java多線程的2種方式,runable是介面,thread是類,建議使用runable實現java多線程,不管如何,最終都需要通過thread.start()來使線程處於可運行狀態。

2、 認識Thread的start和run

1) start:

用start方法來啟動線程,真正實現了多線程運行,這時無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。通過調用Thread類的start()方法來啟動一個線程,這時此線程處於就緒(可運行)狀態,並沒有運行,一旦得到spu時間片,就開始執行run()方法,這里方法run()稱為線程體,它包含了要執行的這個線程的內容,Run方法運行結束,此線程隨即終止。

2) run:

run()方法只是類的一個普通方法而已,如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑還是只有一條,還是要順序執行,還是要等待run方法體執行完畢後才可繼續執行下面的代碼,這樣就沒有達到寫線程的目的。

總結:調用start方法方可啟動線程,而run方法只是thread的一個普通方法調用,還是在主線程里執行。

3、 線程狀態說明

線程狀態從大的方面來說,可歸結為:初始狀態、可運行狀態、不可運行狀態和消亡狀態,具體可細分為上圖所示7個狀態,說明如下:

1) 線程的實現有兩種方式,一是繼承Thread類,二是實現Runnable介面,但不管怎樣,當我們new了thread實例後,線程就進入了初始狀態;

2) 當該對象調用了start()方法,就進入可運行狀態;

3) 進入可運行狀態後,當該對象被操作系統選中,獲得CPU時間片就會進入運行狀態;

4) 進入運行狀態後case就比較多,大致有如下情形:

·run()方法或main()方法結束後,線程就進入終止狀態;

·當線程調用了自身的sleep()方法或其他線程的join()方法,就會進入阻塞狀態(該狀態既停止當前線程,但並不釋放所佔有的資源)。當sleep()結束或join()結束後,該線程進入可運行狀態,繼續等待OS分配時間片;

·當線程剛進入可運行狀態(注意,還沒運行),發現將要調用的資源被鎖牢(synchroniza,lock),將會立即進入鎖池狀態,等待獲取鎖標記(這時的鎖池裡也許已經有了其他線程在等待獲取鎖標記,這時它們處於隊列狀態,既先到先得),一旦線程獲得鎖標記後,就轉入可運行狀態,等待OS分配CPU時間片;

·當線程調用wait()方法後會進入等待隊列(進入這個狀態會釋放所佔有的所有資源,與阻塞狀態不同),進入這個狀態後,是不能自動喚醒的,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒(由於notify()只是喚醒一個線程,但我們由不能確定具體喚醒的是哪一個線程,也許我們需要喚醒的線程不能夠被喚醒,因此在實際使用時,一般都用notifyAll()方法,喚醒有所線程),線程被喚醒後會進入鎖池,等待獲取鎖標記。

·當線程調用stop方法,即可使線程進入消亡狀態,但是由於stop方法是不安全的,不鼓勵使用,大家可以通過run方法里的條件變通實現線程的stop。

閱讀全文

與java線程怎麼用相關的資料

熱點內容
貴州java編譯器 瀏覽:644
歐美電影免費看平台 瀏覽:286
台灣紅羊影視作品有哪些 瀏覽:906
農行app上怎麼查詢卡號 瀏覽:891
浩天酒道館網是什麼app 瀏覽:212
永久不收費的電影網站 瀏覽:120
兒女傳奇全集目錄 瀏覽:522
文學評論pdf 瀏覽:410
linux源代碼導讀 瀏覽:702
百戰程序員6000集下載 瀏覽:146
蘋果和安卓手機之間怎麼克隆 瀏覽:465
模糊聚類演算法研究 瀏覽:108
寶德伺服器硬碟亮紅燈如何解決 瀏覽:696
androidlibgdx下載 瀏覽:409
聯盟pdf下載 瀏覽:793
南通住房公積金app支取銀行怎麼填 瀏覽:680
韓國劇情電影男主自殺2次是什麼電影 瀏覽:646
李彩譚電影全部 瀏覽:703
范偉喬杉電影叫什麼名字 瀏覽:467
中國十大免費電影網站 瀏覽:509