激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術(shù)|正則表達(dá)式|

淺析 Java多線程

2020-09-26 21:21城北有個(gè)混子 JAVA教程

這篇文章主要介紹了Java多線程的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java線程相關(guān)知識(shí),感興趣的朋友可以了解下

什么是進(jìn)程

  當(dāng)一個(gè)程序進(jìn)入內(nèi)存中運(yùn)行起來(lái)它就變?yōu)橐粋€(gè)進(jìn)程。因此,進(jìn)程就是一個(gè)處于運(yùn)行狀態(tài)的程序。同時(shí)進(jìn)程具有獨(dú)立功能,進(jìn)程是操作系統(tǒng)進(jìn)行資源分配和調(diào)度的獨(dú)立單位。

什么是線程

  線程是進(jìn)程的組成部分。通常情況下,一個(gè)進(jìn)程可擁有多個(gè)線程,而一個(gè)線程只能擁有一個(gè)父進(jìn)程。

  線程可以擁有自己的堆棧、自己的程序計(jì)數(shù)器及自己的局部變量,但是線程不能擁有系統(tǒng)資源,它與其父進(jìn)程的其他線程共享進(jìn)程中的全部資源,這其中包括進(jìn)程的代碼段、數(shù)據(jù)段、堆空間以及一些進(jìn)程級(jí)的資源(例如,打開(kāi)的文件等)。

  線程是進(jìn)程的執(zhí)行單元,是CPU調(diào)度和分派的基本單位,當(dāng)進(jìn)程被初始化之后,主線程就會(huì)被創(chuàng)建。同時(shí)如果有需要,還可以在程序執(zhí)行過(guò)程中創(chuàng)建出其他線程,這些線程之間也是相互獨(dú)立的,并且在同一進(jìn)程中并發(fā)執(zhí)行。因此一個(gè)進(jìn)程中可以包含多個(gè)線程,但是至少要包含一個(gè)線程,即主線程。

淺析 Java多線程

Java中的線程

  Java 中使用Thread類表示一個(gè)線程。所有的線程對(duì)象都必須是Thread或其子類的對(duì)象。Thread 類中的 run 方法是該線程的執(zhí)行代碼。讓我們來(lái)看一個(gè)實(shí)例:

?
1
2
3
4
5
6
7
8
public class Ticket extends Thread{
  // 重寫run方法
  public void run() {
    for (int i = 0; i < 20; i++) {
      System.out.println(getName() + ": " + i);
    }
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
public class TestThread {
  public static void main(String[] args) {
    // 1.創(chuàng)建線程
    Thread thread1 = new Ticket();
    Thread thread2 = new Ticket();
    
    // 2.啟動(dòng)線程
    thread1.start();
    thread2.start();
  }
}

運(yùn)行結(jié)果如下:

淺析 Java多線程

 通過(guò)上面的代碼和運(yùn)行結(jié)果,我們可以得到:

線程運(yùn)行的幾個(gè)特點(diǎn)

  1.同一進(jìn)程下不同線程的調(diào)度不由程序控制。線程的執(zhí)行是搶占式的,運(yùn)行的順序和線程的啟動(dòng)順序是無(wú)關(guān)的,當(dāng)前運(yùn)行的線程隨時(shí)都可能被掛起,然后其他進(jìn)程搶占運(yùn)行。

  2.線程獨(dú)享自己的堆棧程序計(jì)數(shù)器和局部變量。兩個(gè)進(jìn)程的局部變量互不干擾,各自的執(zhí)行順序也是互不干擾。

  3.兩個(gè)線程并發(fā)執(zhí)行。兩個(gè)線程同時(shí)向前推進(jìn),并沒(méi)有說(shuō)執(zhí)行完一個(gè)后再執(zhí)行另一個(gè)。

start()方法和run()方法

  啟動(dòng)一個(gè)線程必須調(diào)用Thread 類的 start()方法,使該線程處于就緒狀態(tài),這樣該線程就可以被處理器調(diào)度。

   run()方法是一個(gè)線程所關(guān)聯(lián)的執(zhí)行代碼,無(wú)論是派生自 Thread類的線程類,還是實(shí)現(xiàn)Runnable接口的類,都必須實(shí)現(xiàn)run()方法,run()方法里是我們需要線程所執(zhí)行的代碼。

  實(shí)現(xiàn)多線程必須調(diào)用Thread 類的 start()方法來(lái)啟動(dòng)線程,使線程處于就緒狀態(tài)隨時(shí)供CPU調(diào)度。如果直接調(diào)用run()方法的話,只是調(diào)用了Thread類的一個(gè)普通方法,會(huì)立即執(zhí)行該方法中的代碼,并沒(méi)有實(shí)現(xiàn)多線程技術(shù)。

Java中多線程的實(shí)現(xiàn)方法

  在Java中有三種方法實(shí)現(xiàn)多線程。

    第一種方法:使用Thread類或者使用一個(gè)派生自Thread 類的類構(gòu)建一個(gè)線程。

    第二種方法:實(shí)現(xiàn)Runnable 接口來(lái)構(gòu)建一個(gè)線程。(推薦使用)

    第三種方法:實(shí)現(xiàn)Callable 接口來(lái)構(gòu)建一個(gè)線程。(有返回值)

第一種方法

  使用Thread類或者使用一個(gè)派生自Thread 類的類構(gòu)建一個(gè)線程。

?
1
2
3
4
5
6
7
8
public class Ticket extends Thread{
  // 重寫run方法
  public void run() {
    for (int i = 0; i < 20; i++) {
      System.out.println(getName() + ": " + i);
    }
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
public class TestThread {
  public static void main(String[] args) {
    // 1.創(chuàng)建線程
    Thread thread1 = new Ticket();
    Thread thread2 = new Ticket();
    
    // 2.啟動(dòng)線程
    thread1.start();
    thread2.start();
  }
}

  看上面的代碼,我們創(chuàng)建了一個(gè)Ticket類,它繼承了Thread類,重寫了Thread類的run方法。然后我們用Ticket類創(chuàng)建了兩個(gè)線程,并且啟動(dòng)了它們。但我們不推薦使用這種方法,因?yàn)橐粋€(gè)類繼承了Thread類,那它就沒(méi)有辦法繼承其他類了,這對(duì)較為復(fù)雜的程序開(kāi)發(fā)是不利的。

第二種方法

  實(shí)現(xiàn)Runnable 接口來(lái)構(gòu)建一個(gè)線程。

?
1
2
3
4
5
6
7
8
public class Ticket implements Runnable{
  // 重寫run方法
  public void run() {
    for (int i = 0; i < 20; i++) {
      System.out.println(Thread.currentThread().getName() + ": " + i);
    }
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class TestThread {
  public static void main(String[] args) {
    // 1.創(chuàng)建線程
    Ticket t1 = new Ticket();
    Ticket t2 = new Ticket();
    Thread thread1 = new Thread(t1, "買票1號(hào)");
    Thread thread2 = new Thread(t2, "買票2號(hào)");
    
    // 2.啟動(dòng)線程
    thread1.start();
    thread2.start();
  }
}

  我們創(chuàng)建了一個(gè)Ticket類,實(shí)現(xiàn)了Runnable接口,在該類中實(shí)現(xiàn)了run方法。在啟動(dòng)線程前,我們要?jiǎng)?chuàng)建一個(gè)線程對(duì)象,不同的是我們要將一個(gè)實(shí)現(xiàn)了Runnable接口的類的對(duì)象作為Thread類構(gòu)造方法的參數(shù)傳入,以構(gòu)建線程對(duì)象。構(gòu)造方法Thread的第二個(gè)參數(shù)用來(lái)指定該線程的名字,通過(guò)Thread.currentThread().getName()可獲取當(dāng)前線程的名字。

  在真實(shí)的項(xiàng)目開(kāi)發(fā)中,推薦使用實(shí)現(xiàn)Runnable接口的方法進(jìn)行多線程編程。因?yàn)檫@樣既可以實(shí)現(xiàn)一個(gè)線程的功能,又可以更好地復(fù)用其他類的屬性和方法。

第三種方法

  實(shí)現(xiàn)Callable 接口來(lái)構(gòu)建一個(gè)線程。

?
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
public class TestThread {
  public static void main(String[] args) { 
    // 1.創(chuàng)建Callable的實(shí)例
    Callable<String> callable = new Callable<String>() {
      @Override
      public String call() throws Exception {
        Thread.sleep(7000);
        return "我結(jié)束了";
      }
    };
    
    // 2.通過(guò)FutureTask接口的實(shí)例包裝Callable的實(shí)例
    FutureTask<String> futureTask = new FutureTask<String>(callable);
    
    // 3.創(chuàng)建線程并啟動(dòng)
    new Thread(futureTask).start();
    
    // 4.獲得結(jié)果并打印
    try {
      System.out.println(futureTask.get());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

  首先我們用匿名內(nèi)部類創(chuàng)建了一個(gè)實(shí)現(xiàn)Callable接口的類的對(duì)象,然后通過(guò)FutureTask 的實(shí)例包裝了Callable的實(shí)例,這樣我們就可以通過(guò)一個(gè)Thread 對(duì)象在新線程中執(zhí)行call()方法,同時(shí)又可以通過(guò)get方法獲取到call()的返回值。然后創(chuàng)建線程并啟動(dòng)它,最后在線程執(zhí)行完執(zhí)行完call()方法后得到返回值并打印。

  我們來(lái)看一下Callable的源碼:

?
1
2
3
4
5
6
7
8
9
public interface Callable<V> {
  /**
   * Computes a result, or throws an exception if unable to do so.
   *
   * @return computed result
   * @throws Exception if unable to compute a result
   */
  V call() throws Exception;
}

  從Callable 的定義可以看出,Callable接口是一個(gè)泛型接口,它定義的call()方法類似于Runnable 的run()方法,是線程所關(guān)聯(lián)的執(zhí)行代碼。但是與run()方法不同的是,call()方法具有返回值,并且泛型接口的參數(shù)V指定了call()方法的返回值類型。同時(shí),如果call()方法得不到返回值將會(huì)拋出一個(gè)異常,而在Runnable的run()方法中不能拋出異常。

如何獲得call()方法的返回值

  通過(guò)Future接口來(lái)獲取。Future接口定義了一組對(duì) Runnable 或者Callable 任務(wù)的執(zhí)行結(jié)果進(jìn)行取消、查詢、獲取、設(shè)置的操作。其中g(shù)et方法用于獲取call()的返回值,它會(huì)發(fā)生阻塞,直到call()返回結(jié)果。

這樣的線程調(diào)用與直接同步調(diào)用函數(shù)有什么差異

  在上面的例子中,通過(guò)future.get()獲取 call()的返回值時(shí),由于call方法中會(huì) sleep 7s,所以在執(zhí)行future.get()的時(shí)候主線程會(huì)被阻塞而什么都不做,等待call()執(zhí)行完并得到返回值。但是這與直接調(diào)用函數(shù)獲取返回值還是有本質(zhì)區(qū)別的。

  因?yàn)閏all()方法是運(yùn)行在其他線程里的,在這個(gè)過(guò)程中主線程并沒(méi)有被阻塞,還是可以做其他事情的,除非執(zhí)行future.get()去獲取 call()的返回值時(shí)主線程才會(huì)被阻塞。所以當(dāng)調(diào)用了Thread.start()方法啟動(dòng) Callable 線程后主線程可以執(zhí)行別的工作,當(dāng)需要call()的返回值時(shí)再去調(diào)用future.get()獲取,此時(shí)call()方法可能早已執(zhí)行完畢,這樣就可以既確保耗時(shí)操作在工作線程中完成而不阻擋主線程,又可以得到線程執(zhí)行結(jié)果的返回值。而直接調(diào)用函數(shù)獲取返回值是一個(gè)同步操作,該函數(shù)本身就是運(yùn)行在主線程中,所以一旦函數(shù)中有耗時(shí)操作,必然會(huì)阻擋主線程。

以上就是淺析 Java多線程的詳細(xì)內(nèi)容,更多關(guān)于Java多線程的資料請(qǐng)關(guān)注服務(wù)器之家其它相關(guān)文章!

原文鏈接:https://www.cnblogs.com/ruoli-0/p/13726616.html

延伸 · 閱讀

精彩推薦
  • JAVA教程JavaMail入門教程之創(chuàng)建郵件(2)

    JavaMail入門教程之創(chuàng)建郵件(2)

    這篇文章主要介紹了JavaMail入門教程之創(chuàng)建郵件的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下 ...

    汪先森3992020-07-07
  • JAVA教程Spring與Spring boot的區(qū)別介紹

    Spring與Spring boot的區(qū)別介紹

    Spring Boot框架的核心就是自動(dòng)配置,只要存在相應(yīng)的jar包,Spring就幫我們自動(dòng)配置。接下來(lái)通過(guò)本文給大家介紹Spring與Spring boot的區(qū)別介紹,非常不錯(cuò),需要...

    Java教程網(wǎng)2632020-09-08
  • JAVA教程深入解析Java接口(interface)的使用

    深入解析Java接口(interface)的使用

    這篇文章主要介紹了深入解析Java接口(interface)的使用,是Java入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下 ...

    goldensun5052020-01-06
  • JAVA教程Java 泛型實(shí)例詳解

    Java 泛型實(shí)例詳解

    本文主要介紹Java 泛型的知識(shí),這里給代碼實(shí)例對(duì)Java 泛型深度理解,有需要的朋友可以看下 ...

    JAVA教程網(wǎng)4622020-05-29
  • JAVA教程java開(kāi)發(fā)中如何使用JVisualVM進(jìn)行性能分析

    java開(kāi)發(fā)中如何使用JVisualVM進(jìn)行性能分析

    JVisualVM是由Sun提供的性能分析工具,如此強(qiáng)大的后盾怎能不強(qiáng)大?在Jdk6.0以后的版本中是自帶的,配置好環(huán)境變量然后在運(yùn)行中輸入“JVisualVm”或直接到...

    mdxy-dxy5212020-03-14
  • JAVA教程簡(jiǎn)單的java圖片處理類(圖片水印 圖片縮放)

    簡(jiǎn)單的java圖片處理類(圖片水印 圖片縮放)

    本圖片處理類功能非常之強(qiáng)大可以實(shí)現(xiàn)幾乎所有WEB開(kāi)發(fā)中對(duì)圖像的處理功能都集成了,包括有縮放圖像、切割圖像、圖像類型轉(zhuǎn)換、彩色轉(zhuǎn)黑白、文字水印...

    java代碼網(wǎng)4842019-10-20
  • JAVA教程詳解Java中的 枚舉與泛型

    詳解Java中的 枚舉與泛型

    這篇文章主要介紹了 詳解Java中的 枚舉與泛型的相關(guān)資料,需要的朋友可以參考下...

    Java之家1182020-08-22
  • JAVA教程深入理解Spring Boot的日志管理

    深入理解Spring Boot的日志管理

    這篇文章主要給大家深入的介紹了Spring Boot日志管理的相關(guān)資料,文中介紹的很詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。 ...

    橘子不酸2652020-08-05
主站蜘蛛池模板: 免费视频www在线观看 | 亚洲精品有限 | av免费在线观看免费 | 91精品国产成人 | 一级做a爱片性色毛片高清 国产精品色在线网站 | 神马久久蜜桃 | 综合网天天射 | 亚洲综合色视频在线观看 | 国产一区视频在线观看免费 | 毛片福利 | 国产免费小视频在线观看 | 最新午夜综合福利视频 | 中文字幕观看 | 最新中文字幕日本 | 亚洲黑人在线观看 | 免费国产 | 一区二区精品视频在线观看 | 久久精品成人免费国产片桃视频 | 九九热视频这里只有精品 | 欧美精品成人一区二区在线观看 | 高清国产一区二区三区四区五区 | 日日做夜夜操 | 国产免费乱淫av | 欧美精品久久久久久久久老牛影院 | 超碰在线97国产 | 一级在线 | 黄色成人小视频 | 国产一级二级在线播放 | 色中色在线播放 | 久久国产不卡 | 一区二区三区精品国产 | 一级免费看片 | 中国av免费在线观看 | 91av网址 | 9999精品| 黄色大片大毛片 | 在线无码 | 国产午夜精品久久久久 | av国语 | 国产精品欧美日韩一区二区 | 久久国产成人精品国产成人亚洲 |