一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

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

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - Java教程 - 聊聊Java中是什么方法導致的線程阻塞

聊聊Java中是什么方法導致的線程阻塞

2021-08-10 12:07Chin_style Java教程

這篇文章主要介紹了聊聊Java中是什么方法導致的線程阻塞,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

一、為什么引入線程阻塞機制?

為了解決對共享存儲區的訪問沖突,Java 引入了同步機制,現在讓我們來考察多個線程對共享資源的訪問,顯然同步機制已經不夠了,因為在任意時刻所要求的資源不一定已經準備好了被訪問,反過來,同一時刻準備好了的資源也可能不止一個。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支持

阻塞指的是暫停一個線程的執行以等待某個條件發生(如某資源就緒),學過操作系統的同學對它一定已經很熟悉了。Java 提供了大量方法來支持阻塞,下面讓我們逐一分析。

二、Java中實現線程阻塞的方法:

(1)線程睡眠:Thread.sleep (long millis)方法,使線程轉到阻塞狀態。millis參數設定睡眠的時間,以毫秒為單位。當睡眠結束后,就轉為就緒(Runnable)狀態。sleep()平臺移植性好。

(2)線程等待:Object類中的wait()方法,導致當前的線程等待,直到其他線程調用此對象的 notify() 喚醒方法。這個兩個喚醒方法也是Object類中的方法,行為等價于調用 wait() 一樣。wait() 和 notify() 方法:兩個方法配套使用,wait() 使得線程進入阻塞狀態,它有兩種形式,一種允許 指定以毫秒為單位的一段時間作為參數,另一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程重新進入可執行狀態,后者則必須對應的 notify() 被調用.

(3)線程禮讓,Thread.yield() 方法,暫停當前正在執行的線程對象,把執行機會讓給相同或者更高優先級的線程。yield() 使得線程放棄當前分得的 CPU 時間,但是不使線程阻塞,即線程仍處于可執行狀態,隨時可能再次分得 CPU 時間。調用 yield() 的效果等價于調度程序認為該線程已執行了足夠的時間從而轉到另一個線程.

(4)線程自閉,join()方法,等待其他線程終止。在當前線程中調用另一個線程的join()方法,則當前線程轉入阻塞狀態,直到另一個進程運行結束,當前線程再由阻塞轉為就緒狀態。

(5)suspend() 和 resume() 方法:兩個方法配套使用,suspend()使得線程進入阻塞狀態,并且不會自動恢復,必須其對應的resume() 被調用,才能使得線程重新進入可執行狀態。典型地,suspend() 和 resume() 被用在等待另一個線程產生的結果的情形:測試發現結果還沒有產生后,讓線程阻塞,另一個線程產生了結果后,調用 resume() 使其恢復。Thread中suspend()和resume()兩個方法在JDK1.5中已經廢除,不再介紹。因為有死鎖傾向。

這里,筆者放入一張線程生命周期的經典圖片,來幫助讀者理解,里面展示了一個線程從創建->運行->阻塞->運行->死亡的全過程:

聊聊Java中是什么方法導致的線程阻塞

三、常用線程名詞解釋

主線程:JVM調用程序main()所產生的線程。

當前線程:這個是容易混淆的概念。一般指通過Thread.currentThread()來獲取的進程。

后臺線程:指為其他線程提供服務的線程,也稱為守護線程。JVM的垃圾回收線程就是一個后臺線程。用戶線程和守護線程的區別在于,是否等待主線程依賴于主線程結束而結束

前臺線程:是指接受后臺線程服務的線程,其實前臺后臺線程是聯系在一起,就像傀儡和幕后操縱者一樣的關系。傀儡是前臺線程、幕后操縱者是后臺線程。由前臺線程創建的線程默認也是前臺線程。可以通過isDaemon()和setDaemon()方法來判斷和設置一個線程是否為后臺線程。

可見進程:可見進程是指一些不在前臺,但用戶依然可見的進程,舉例來說:各種widget、輸入法等,都屬于visibe。這部分進程雖然不在前臺,但與我們的使用也是密切相關,我們并不希望它被系統終止。

“前臺可見進程服務于后臺空進程”——這是記錄線程重要性的口訣,

重要性一次遞減即,前臺進程>可見進程>服務進程>后臺進程>空進程。

線程類的一些常用方法:

sleep(): 強迫一個線程睡眠N毫秒。

isAlive(): 判斷一個線程是否存活。

join(): 等待線程終止。

activeCount(): 程序中活躍的線程數。

enumerate(): 枚舉程序中的線程。

currentThread(): 得到當前線程。

isDaemon(): 一個線程是否為守護線程。

setDaemon(): 設置一個線程為守護線程。(用戶線程和守護線程的區別在于,是否等待主線程依賴于主線程結束而結束)

setName(): 為線程設置一個名稱。

wait(): 強迫一個線程等待。

notify(): 通知一個線程繼續運行。

setPriority(): 設置一個線程的優先級。

補充:java處理線程阻塞的小技巧

在java中我們使用多線程去處理一些業務,如果業務比較復雜且當并發量有挺大的時候,很有可能出現線程阻塞的問題。

案例:

有一個觸發接口,根據觸發的信息內部開啟多個線程去執行業務,每個線程都會去執行兩種業務:私有業務(比如調用不同的接口)、公共業務(比如執行存儲、mq發送等等),當私有業務處理時間很快而公共業務處理時間比較長,這樣的情景下就可以把私有業務和公共業務分到不同線程執行。

例如:

當觸發了這個接口,根據接口觸發的信息,需要開啟10個線程,那么就可以創建10個線程去執行它的私有業務,然后再額外創建一個線程去拿到前面那10個線程的執行返回結果并進行公共業務的處理。

這樣有個好處,就是能讓線程池很快的回收線程,能有效防止線程的阻塞

量化:

單個私有業務1秒鐘能執行完成,單個公共業務需要5秒鐘才能執行完成,如果接口被觸發,發現需要創建100個線程執行,那么線程池回收這些線程池至少需要等待6秒,如果按照前面說的分成兩個線程,那么就需要創建101個線程,而1秒后就能回收掉執行完成的100個線程

但是這里需要做權衡,如果接口被觸發的時候發現需要開啟的線程比較多且公共業務很耗時,這種情況下執行公共業務只有單個線程同步執行,那么這個線程就會執行比較長的時間,所以執行公共業務的時候也可根據實際情況開啟多個線程。

下面寫了個小demo:

1.私有業務的類:

?
1
2
3
4
5
6
7
@Component
public class Calculation {
  public Result cal(String req, int a, int b) {
    System.out.println("請求id:" + req + "  結果:" + (a + b));
    return new Result(req, a + b);
  }
}

2.公共業務的類:

?
1
2
3
4
5
6
7
8
9
10
11
@Component
public class SomethingElse {
  public void doElse(Result result) {
    try {
      System.out.println(Thread.currentThread().getName() + " : 開始做其他事情,請求號:" + result.getReq() + " ,請求結果:" + result.getSum());
      Thread.sleep(2000);
      System.out.println(Thread.currentThread().getName() + " : 完成做其他事情,請求號:" + result.getReq() + " ,請求結果:" + result.getSum());
    } catch (InterruptedException e) {
    }
  }
}

3.私有業務的線程類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CallTask implements Callable<Result> {
  private String req;
  private int a;
  private int b;
  @Override
  public Result call() throws Exception {
    Calculation calculation = Main.applicationContext.getBean(Calculation.class);
    return calculation.cal(req, a, b);
  }
  public CallTask(String req, int a, int b) {
    this.req = req;
    this.a = a;
    this.b = b;
  }
  // getter and setter 等等
}

4.公共業務的線程類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ElseTask implements Runnable {
  private CompletionService<Result> cs;
  private int threadCount;
  public ElseTask(CompletionService<Result> cs, int threadCount) {
    this.cs = cs;
    this.threadCount = threadCount;
  }
  @Override
  public void run() {
    SomethingElse somethingElse = Main.applicationContext.getBean(SomethingElse.class);
    doElse(somethingElse);
  }
  private void doElse(SomethingElse somethingElse) {
    try {
      for (int i = 0; i < threadCount; i++) {
        Future<Result> take = cs.take();
        Result result = take.get();
        somethingElse.doElse(result);
      }
    } catch (Exception e) {
    }
  }
  // getter and setter 等等
}

6.測試主方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Service
public class Main implements ApplicationContextAware {
  public static ApplicationContext applicationContext = null;
  public static void main(String[] args) throws InterruptedException {
    AbstractApplicationContext appContext = new ClassPathXmlApplicationContext("application01.xml");
    ExecutorService executorService = Executors.newFixedThreadPool(100);
    CompletionService<Result> cs = new ExecutorCompletionService(executorService);
    //這里啟動執行計算的線程
    cs.submit(new CallTask("req001", 0, 1));
    cs.submit(new CallTask("req002", 0, 2));
    cs.submit(new CallTask("req003", 0, 3));
    cs.submit(new CallTask("req004", 0, 4));
    cs.submit(new CallTask("req005", 0, 5));
    //專門的監控線程,并執行其他耗時的線程
    executorService.execute(new ElseTask(cs, 5));
    executorService.shutdown();
    appContext.registerShutdownHook();
  }
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
  }
}

執行結果如下:

聊聊Java中是什么方法導致的線程阻塞

核心思想: 將多線程的公有的業務抽出來(前提是公有業務比較耗時,不然就沒必要了)在其他線程里面執行。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。如有錯誤或未考慮完全的地方,望不吝賜教。

原文鏈接:https://blog.csdn.net/weixin_41101173/article/details/79679300

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成人毛片高清视频观看 | 国产成人h视频在线播放网站 | 精品国产乱码久久久人妻 | 日本中文字幕在线视频 | 美女和男生搞基 | 亚洲 欧美 国产 日韩 字幕 | 成人操| 男人与雌性宠物交啪啪小说 | 近亲乱中文字幕 | 超级乱淫寡妇 | 国产欧美日韩不卡一区二区三区 | 动漫美女被褥吸奶漫画漫画 | 日韩视频一区二区三区 | 无人区在线观看免费国语完整版 | 哇嘎在线精品视频在线观看 | 成人精品福利 | 猛操美女| 亚洲国产精品91 | 吉川爱美与黑人解禁 | 精品亚洲一区二区三区在线播放 | 999精品视频在线 | 久久精品熟女亚洲AV国产 | 91最新入口| 日本视频二区 | 国产一区二区三区水野朝阳 | 成人综合婷婷国产精品久久免费 | 欧美18-19sex性处视频 | 男人搡女人视频免费看 | 丝瓜视频看污片 | 四虎视屏 | 精品一区二区三区五区六区七区 | 美女视频一区二区三区在线 | 亚洲 综合 欧美在线 热 | 热国产热综合 | 男人影院天堂网址 | 国产91素人搭讪系列天堂 | 4438全国免费观看 | 香蕉在线精品一区二区 | 天美影视文化传媒mv免费 | 91会员 | 天天天综合网 |