国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

香港云服务器
服務器之家 - 編程語言 - JAVA教程 - Java 多線程實例講解(一)

Java 多線程實例講解(一)

2020-06-11 15:07Corn JAVA教程

本文主要介紹Java 多線程的知識,這里整理了詳細的資料及簡單示例代碼有需要的小伙伴可以參考下

Java多線程(一)

多線程作為Java中很重要的一個知識點,在此還是有必要總結一下的。

一.線程的生命周期及五種基本狀態

關于Java中線程的生命周期,首先看一下下面這張較為經典的圖:

Java 多線程實例講解(一)

上圖中基本上囊括了Java中多線程各重要知識點。掌握了上圖中的各知識點,Java中的多線程也就基本上掌握了。主要包括:

Java線程具有五中基本狀態

新建狀態(New):當線程對象對創建后,即進入了新建狀態,如:Thread t = new MyThread();

就緒狀態(Runnable):當調用線程對象的start()方法(t.start();),線程即進入就緒狀態。處于就緒狀態的線程,只是說明此線程已經做好了準備,隨時等待CPU調度執行,并不是說執行了t.start()此線程立即就會執行;

運行狀態(Running):當CPU開始調度處于就緒狀態的線程時,此時線程才得以真正執行,即進入到運行狀態。注:就     緒狀態是進入到運行狀態的唯一入口,也就是說,線程要想進入運行狀態執行,首先必須處于就緒狀態中;

阻塞狀態(Blocked):處于運行狀態中的線程由于某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU調用以進入到運行狀態。根據阻塞產生的原因不同,阻塞狀態又可以分為三種:

1.等待阻塞:運行狀態中的線程執行wait()方法,使本線程進入到等待阻塞狀態;

2.同步阻塞 -- 線程在獲取synchronized同步鎖失敗(因為鎖被其它線程所占用),它會進入同步阻塞狀態;

3.其他阻塞 -- 通過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入就緒狀態。

死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。

二. Java多線程的創建及啟動

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

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

?
1
2
3
4
5
6
7
8
9
10
11
class MyThread extends Thread {
 
 private int i = 0;
 
 @Override
 public void run() {
 for (i = 0; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
 }
 }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ThreadTest {
 
 public static void main(String[] args) {
 for (int i = 0; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
  if (i == 30) {
  Thread myThread1 = new MyThread(); // 創建一個新的線程 myThread1 此線程進入新建狀態
  Thread myThread2 = new MyThread(); // 創建一個新的線程 myThread2 此線程進入新建狀態
  myThread1.start();   // 調用start()方法使得線程進入就緒狀態
  myThread2.start();   // 調用start()方法使得線程進入就緒狀態
  }
 }
 }
}

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

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

?
1
2
3
4
5
6
7
8
9
10
class MyRunnable implements Runnable {
 private int i = 0;
 
 @Override
 public void run() {
 for (i = 0; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
 }
 }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ThreadTest {
 
 public static void main(String[] args) {
 for (int i = 0; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
  if (i == 30) {
  Runnable myRunnable = new MyRunnable(); // 創建一個Runnable實現類的對象
  Thread thread1 = new Thread(myRunnable); // 將myRunnable作為Thread target創建新的線程
  Thread thread2 = new Thread(myRunnable);
  thread1.start(); // 調用start()方法使得線程進入就緒狀態
  thread2.start();
  }
 }
 }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class ThreadTest {
 
 public static void main(String[] args) {
 for (int i = 0; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
  if (i == 30) {
  Runnable myRunnable = new MyRunnable();
  Thread thread = new MyThread(myRunnable);
  thread.start();
  }
 }
 }
}
 
class MyRunnable implements Runnable {
 private int i = 0;
 
 @Override
 public void run() {
 System.out.println("in MyRunnable run");
 for (i = 0; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
 }
 }
}
 
class MyThread extends Thread {
 
 private int i = 0;
 
 public MyThread(Runnable runnable){
 super(runnable);
 }
 
 @Override
 public void run() {
 System.out.println("in MyThread run");
 for (i = 0; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
 }
 }
}

同樣的,與實現Runnable接口創建線程方式相似,不同的地方在于

1 Thread thread = new MyThread(myRunnable);

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

?
1
2
3
4
5
public interface Runnable {
 
public abstract void run();
 
}

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

?
1
2
3
4
5
6
@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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class ThreadTest {
 
 public static void main(String[] args) {
 
 Callable<Integer> myCallable = new MyCallable(); // 創建MyCallable對象
 FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask來包裝MyCallable對象
 
 for (int i = 0; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
  if (i == 30) {
  Thread thread = new Thread(ft); //FutureTask對象作為Thread對象的target創建新的線程
  thread.start();   //線程進入到就緒狀態
  }
 }
 
 System.out.println("主線程for循環執行完畢..");
 
 try {
  int sum = ft.get();  //取得新創建的新線程中的call()方法返回的結果
  System.out.println("sum = " + sum);
 } catch (InterruptedException e) {
  e.printStackTrace();
 } catch (ExecutionException e) {
  e.printStackTrace();
 }
 
 }
}
 
 
class MyCallable implements Callable<Integer> {
 private int i = 0;
 
 // 與run()方法不同的是,call()方法具有返回值
 @Override
 public Integer call() {
 int sum = 0;
 for (; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
  sum += i;
 }
 return sum;
 }
 
}

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

?
1
2
3
4
5
public class FutureTask<V> implements RunnableFuture<V> {
 
 //....
 
 }
?
1
2
3
4
5
public interface RunnableFuture<V> extends Runnable, Future<V> {
 
 void run();
 
 }

于是,我們發現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多線程的就緒、運行和死亡狀態

就緒狀態轉換為運行狀態:當此線程得到處理器資源;

運行狀態轉換為就緒狀態:當此線程主動調用yield()方法或在運行過程中失去處理器資源。

運行狀態轉換為死亡狀態:當此線程線程執行體執行完畢或發生了異常。

此處需要特別注意的是:當調用線程的yield()方法時,線程從運行狀態轉換為就緒狀態,但接下來CPU調度就緒狀態中的哪個線程具有一定的隨機性,因此,可能會出現A線程調用了yield()方法后,接下來CPU仍然調度了A線程的情況。

由于實際的業務需要,常常會遇到需要在特定時機終止某一線程的運行,使其進入到死亡狀態。目前最通用的做法是設置一boolean型的變量,當條件滿足時,使線程執行體快速執行完畢。如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class ThreadTest {
 
 public static void main(String[] args) {
 
 MyRunnable myRunnable = new MyRunnable();
 Thread thread = new Thread(myRunnable);
 
 for (int i = 0; i < 100; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
  if (i == 30) {
  thread.start();
  }
  if(i == 40){
  myRunnable.stopThread();
  }
 }
 }
}
 
class MyRunnable implements Runnable {
 
 private boolean stop;
 
 @Override
 public void run() {
 for (int i = 0; i < 100 && !stop; i++) {
  System.out.println(Thread.currentThread().getName() + " " + i);
 }
 }
 
 public void stopThread() {
 this.stop = true;
 }
 
}

后續繼續整理相關文章,謝謝大家對本站的支持!

延伸 · 閱讀

精彩推薦
323
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 国产精品99久久久久久久女警 | 日韩一区二区不卡 | 国产99精品在线 | 亚洲综合视频在线观看 | 超碰在线91 | 成人国内精品久久久久一区 | 99精品一区二区 | 91视视频在线观看入口直接观看 | 亚洲精品视频国产 | 天堂v视频 | 亚洲小视频| 99精品欧美一区二区三区综合在线 | 色先锋av资源中文字幕 | 成人精品在线 | 欧美一区二区久久 | 精品国精品国产自在久不卡 | 欧美日韩成人网 | 精品久久精品 | 精品视频在线免费观看 | 色视频在线看 | 国产在线精品一区 | 最好看的2019年中文在线观看 | 中文字幕免费视频 | 天天插天天操 | 久草在线| 色综合久久88色综合天天 | 亚洲一区二区三区四区的 | 国产资源免费观看 | 九色91| 亚洲精品日韩激情在线电影 | 久久久久久久久成人 | www.777色| 久久窝 | 国产精品美女久久久久高潮 | 黄色成人av| 视频三区| 欧美日韩精品电影 | 羞羞视频在线 | 超碰天天 | 成人在线观看网站 | 亚洲国产综合在线 |