最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的多線程一定就快嗎?

 更新時間:2020年09月09日 10:00:38   作者:崔笑顏  
這篇文章主要介紹了Java 多線程的相關(guān)資料,幫助大家是否選擇開啟多線程,感興趣的朋友可以了解下

并發(fā)編程與多線程編程

要了解并發(fā)編程,首先要懂得與并行這個概念進行區(qū)分。并行是指兩個事件同時進行,并發(fā)是CPU切換速度快,看起來像是每個任務(wù)同時進行一樣。多線程是實現(xiàn)并發(fā)編程的一種方式,假設(shè)一個場景,在廣州地鐵高峰時段,一群人涌進地鐵里,在不同的閘機口刷卡進去。在這個場景里,進地鐵就是任務(wù),每個人可以看出是并發(fā)的,而多個刷卡閘機口就是多線程。

  并發(fā)編程的本質(zhì)目的是為了充分利用CPU,讓程序運行得更快。然而,并不是啟動更多的線程就能讓程序最大限度地并發(fā)執(zhí)行。在進行并發(fā)編程時,如果希望通過多線程執(zhí)行任務(wù)讓程序運行得更快,會面臨非常多的挑戰(zhàn)。比如上下文切換的問題、死鎖的問題,以及受限于硬件和軟件的資源限制問題,下面就來嘮嗑嘮嗑這些因素。

上下文切換

原理分析

正如上面所言,并發(fā)與并行最大的區(qū)別就是,并發(fā)只是看起來像是并行。實際上是,CPU通過給每個線程分配時間來執(zhí)行這個線程的程序,只是這個時間非常短,通常是幾十毫秒,我們根本無法觀察到變化,感覺它們都是同時執(zhí)行的一樣。

  CPU通過時間片分配算法來循環(huán)執(zhí)行任務(wù),當前任務(wù)執(zhí)行一個時間片后會切換到下一個任務(wù)。但是,在切換前會保存上一個任務(wù)的狀態(tài),以便下次切換回這個任務(wù)時,可以再加載這個任務(wù)的狀態(tài)。所以任務(wù)從保存到再加載的過程就是一次上下文切換。因此,不難得知,上下文切換需要耗費不少時間。

  再來假設(shè)一個場景,一個人去火車站買票,買票的窗口有十來個那么多。買票的人并不知道哪個窗口可以買到票,只能挨個地問,最后終于在最后一個窗口買到了。這個場景,看似買票的過程很長,其實大部分時間都在切換窗口上,這也就是上下文切換的問題所在。因此,并非線程數(shù)多就一定執(zhí)行得快,要選擇與任務(wù)相適應(yīng)的線程數(shù)才是最佳方案。

測試代碼

package Concurrency;

/**
 * @author RuiMing Lin
 * @date 2020-03-28 12:19
 */
public class Demo1 {
  public static void main(String[] args) {
    System.out.println("萬級循環(huán):");
    concurrency(10000);
    serial(10000);
    System.out.println("--------------------------華麗分隔符--------------------------------");
    System.out.println("十萬級循環(huán):");
    concurrency(100000);
    serial(100000);
    System.out.println("--------------------------華麗分隔符--------------------------------");
    System.out.println("百萬級循環(huán):");
    concurrency(1000000);
    serial(1000000);
    System.out.println("--------------------------華麗分隔符--------------------------------");
    System.out.println("千萬級循環(huán):");
    concurrency(10000000);
    serial(10000000);
    System.out.println("--------------------------華麗分隔符--------------------------------");
    System.out.println("億級循環(huán):");
    concurrency(100000000);
    serial(100000000);
  }

  private static void concurrency(long count){
    // 開啟三個線程執(zhí)行三個循環(huán)
    long start = System.currentTimeMillis();
    new Thread(new Runnable() {
      @Override
      public void run() {
        int a = 0;
        for (long i = 0; i < count; i++) {
          a++;
        }
      }
    }).start();
    new Thread(new Runnable() {
      @Override
      public void run() {
        int b = 0;
        for (long i = 0; i < count; i++) {
          b++;
        }
      }
    }).start();
    new Thread(new Runnable() {
      @Override
      public void run() {
        int c = 0;
        for (long i = 0; i < count; i++) {
          c++;
        }
      }
    }).start();
    long end = System.currentTimeMillis();
    long time = end - start;
    System.out.println("并行執(zhí)行花費時間為:" + time + "ms");
  }

  private static void serial(long count){
    // 三個循環(huán)順序執(zhí)行
    long start = System.currentTimeMillis();
    int a = 0;
    int b = 0;
    int c = 0;
    for (int i = 0; i < count; i++) {
      a++;
    }
    for (int i = 0; i < count; i++) {
      b++;
    }
    for (int i = 0; i < count; i++) {
      c++;
    }
    long end = System.currentTimeMillis();
    long time = end - start;
    System.out.println("串行執(zhí)行花費時間為:" + time + "ms");
  }
}

結(jié)果輸出:

萬級循環(huán): 并行執(zhí)行花費時間為:4ms 串行執(zhí)行花費時間為:1ms

--------------------------華麗分隔符--------------------------------

十萬級循環(huán): 并行執(zhí)行花費時間為:1ms 串行執(zhí)行花費時間為:4ms

--------------------------華麗分隔符--------------------------------

百萬級循環(huán): 并行執(zhí)行花費時間為:1ms 串行執(zhí)行花費時間為:10ms

--------------------------華麗分隔符--------------------------------

千萬級循環(huán): 并行執(zhí)行花費時間為:1ms 串行執(zhí)行花費時間為:36ms

--------------------------華麗分隔符--------------------------------

億級循環(huán): 并行執(zhí)行花費時間為:1ms 串行執(zhí)行花費時間為:357ms

分析結(jié)果:

當數(shù)量級在萬級時,串行是比并發(fā)要快的,當數(shù)量級來到十萬以后,串行便顯得力不從心了。所以,可以認為當程序執(zhí)行量不夠大時,是沒必要開啟多線程的。

如何減少上下文切換

減少上下文切換的方法有無鎖并發(fā)編程、CAS算法、使用最少線程和使用協(xié)程。

  1. 無鎖并發(fā)編程。多線程競爭鎖時,會引起上下文切換,所以多線程處理數(shù)據(jù)時,可以用一些辦法來避免使用鎖,如將數(shù)據(jù)的ID按照Hash算法取模分段,不同的線程處理不同段的數(shù)據(jù)。
  2. CAS算法。Java的Atomic包使用CAS算法來更新數(shù)據(jù),而不需要加鎖。
  3. 使用最少線程。避免創(chuàng)建不需要的線程,比如任務(wù)很少,但是創(chuàng)建了很多線程來處理,這樣會造成大量線程都處于等待狀態(tài)。
  4. 協(xié)程:在單線程里實現(xiàn)多任務(wù)的調(diào)度,并在單線程里維持多個任務(wù)間的切換。

死鎖

原理分析

 死鎖,是指多個線程在運行過程中因爭奪相同資源而造成的一種僵局,當進程處于這種僵持狀態(tài)時,它們都將無法再向前推進,此時程序就處于癱瘓狀態(tài),無法執(zhí)行。 通常情況下,是多個線程共同競爭同一把鎖對象,而其中一個線程獲得鎖之后發(fā)生異常等未來得及釋放鎖,導(dǎo)致其它線程一直在等待,無法運行。

測試代碼

package Concurrency;

/**
 * @author RuiMing Lin
 * @date 2020-03-28 13:14
 */
public class Demo2 {
  private static String str1 = "A";
  private static String str2 = "B";

  public static void main(String[] args) {
    new Thread(new Runnable() {
      @Override
      public void run() {
        synchronized (str1){
          System.out.println("第一個線程獲得str1");
          try {
            Thread.currentThread().sleep(2000);
          }catch (InterruptedException e){
            e.printStackTrace();
          }
          synchronized (str2){
            System.out.println("第一個線程獲得str2");
          }
        }
      }
    }).start();

    new Thread(new Runnable() {
      @Override
      public void run() {
        synchronized (str2){
          System.out.println("第二個線程獲得str2");
          try {
            Thread.currentThread().sleep(2000);
          }catch (InterruptedException e){
            e.printStackTrace();
          }
          synchronized (str1){
            System.out.println("第二個線程獲得str1");
          }
        }
      }
    }).start();
  }
}

結(jié)果輸出:

如何解決死鎖

  1. 避免一個線程同時獲取多個鎖。
  2. 避免一個線程在鎖內(nèi)同時占用多個資源,盡量保證每個鎖只占用一個資源。
  3. 嘗試使用定時鎖,使用lock.tryLock(timeout)來替代使用內(nèi)部鎖機制。
  4. 對于數(shù)據(jù)庫鎖,加鎖和解鎖必須在一個數(shù)據(jù)庫連接里,否則會出現(xiàn)解鎖失敗的情況。

總結(jié)

并發(fā)程序并不是簡單的程序,編寫的時候應(yīng)該嚴謹一些。復(fù)雜的代碼容易引起死鎖,因此,建議多使用JDK并發(fā)包提供的并發(fā)容器和工具類來解決并發(fā)問題。同時,也要注重新能上的問題,既要考慮到程序執(zhí)行任務(wù)量,也要考慮CPU性能等等,不要一昧地增加線程數(shù)。

以上就是Java中的多線程一定就快嗎?的詳細內(nèi)容,更多關(guān)于Java 多線程的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • SpringMVC中redirect重定向(帶參數(shù))的3種方式

    SpringMVC中redirect重定向(帶參數(shù))的3種方式

    Spring MVC中做form表單功能提交時,防止用戶客戶端后退或者刷新時重復(fù)提交問題,需要在服務(wù)端進行重定向跳轉(zhuǎn),本文主要介紹了SpringMVC中redirect重定向(帶參數(shù))的3種方式,感興趣的可以了解一下
    2024-07-07
  • spring boot入門開始你的第一個應(yīng)用

    spring boot入門開始你的第一個應(yīng)用

    這篇文章主要介紹了spring boot入門開始你的第一個應(yīng)用,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,,需要的朋友可以參考下
    2019-06-06
  • java構(gòu)造方法的互相調(diào)用方式

    java構(gòu)造方法的互相調(diào)用方式

    這篇文章主要介紹了java構(gòu)造方法的互相調(diào)用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • JAVA實現(xiàn)雙向鏈表的增刪功能的方法

    JAVA實現(xiàn)雙向鏈表的增刪功能的方法

    本篇文章主要介紹了JAVA實現(xiàn)雙向鏈表的增刪功能的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-03-03
  • Java中File與byte[]的互轉(zhuǎn)方式

    Java中File與byte[]的互轉(zhuǎn)方式

    這篇文章主要介紹了Java中File與byte[]的互轉(zhuǎn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Java多線程教程之如何利用Future實現(xiàn)攜帶結(jié)果的任務(wù)

    Java多線程教程之如何利用Future實現(xiàn)攜帶結(jié)果的任務(wù)

    Callable與Future兩功能是Java?5版本中加入的,這篇文章主要給大家介紹了關(guān)于Java多線程教程之如何利用Future實現(xiàn)攜帶結(jié)果任務(wù)的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • 淺析spring定時器的使用

    淺析spring定時器的使用

    這篇文章主要介紹了淺析spring定時器的使用,幫助大家更好的理解和學(xué)習(xí)spring框架,感興趣的朋友可以了解下
    2020-10-10
  • Java實現(xiàn)MD5加密的方式與實例代碼

    Java實現(xiàn)MD5加密的方式與實例代碼

    MD5加密是一種常見的加密方式,我們經(jīng)常用在保存用戶密碼和關(guān)鍵信息上。那么它到底有什么,又什么好處呢,會被這么廣泛的運用在應(yīng)用開發(fā)中
    2021-10-10
  • Spring中的set注入方法

    Spring中的set注入方法

    這篇文章主要介紹了Spring中的set注入方法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • SpringCloud OpenFeign 自定義響應(yīng)解碼器的問題記錄

    SpringCloud OpenFeign 自定義響應(yīng)解碼器的問題記錄

    我們在使用 Spring Cloud 微服務(wù)的時候,通常將返回結(jié)果使用一個JsonResult 類進行封裝,本文重點介紹SpringCloud OpenFeign 自定義響應(yīng)解碼器的問題記錄,感興趣的朋友跟隨小編一起看看吧
    2024-06-06

最新評論

长子县| 凯里市| 特克斯县| 芦溪县| 西宁市| 周口市| 新安县| 芦山县| 澎湖县| 敦化市| 磐安县| 镇赉县| 米泉市| 沅江市| 岑溪市| 石门县| 静安区| 上栗县| 香港 | 定远县| 怀柔区| 盘锦市| 阳城县| 本溪市| 永昌县| 竹山县| 东乌珠穆沁旗| 浪卡子县| 垫江县| 永康市| 临桂县| 鲁甸县| 伊宁县| 定远县| 夏邑县| 盘锦市| 通城县| 田阳县| 海淀区| 锡林浩特市| 喀什市|