日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

Java高并发编程-剖析线程启动的start方法

發布時間:2023/12/3 综合教程 35 生活家
生活随笔 收集整理的這篇文章主要介紹了 Java高并发编程-剖析线程启动的start方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

這篇文章,帶著大家來分析一下線程啟動的start()方法,并且簡單地講解一下模板設計模式在線程類中的使用。

在之前分析中,我們知道線程從NEW狀態進入到RUNNABLE裝需要調用start()方法,但是當線程調用完start()方法之后到底進行了那些操作呢?在之前的例子中,我們將業務邏輯代碼寫到了run()方法中,但是實際上執行線程調用的時候卻是執行的是線程的start()方法,兩者之間又有什么聯系呢?

下面我們就來分析一下。

Thread start方法源碼分析

Thread 類的start方法源碼如下所示。

public synchronized void start() { if (threadStatus != 0) throw new IllegalThreadStateException(); group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { } } }

通過源碼可以看出來,源碼邏輯相對比較簡單,其中最主要的一個代碼就是start0()方法。在源碼中可以看到start0(),代碼如下所示。

private native void start0();

也就是說,在我們調用了start()方法之后,會調用start0()方法,還是沒有發現run()方法是什么時候被執行的,但是查看JDK的文檔之后,我們會知道,其實這里的start0()方法其實是通過JNI技術進行調用的,而run()方法也是被JNI的start0()方法。閱讀源碼之后會有如下的一些問題。

  • 當我們new一個線程之后,threadStatus 屬性的值應該是默認為0的,當不等于0的時候就會拋出異常。這個在源碼中說得比較清楚。threadStatus為零表示這個當前狀態是NEW
  • 根據threadStatus的狀態可以知道,不能進行兩次啟動線程操作,也就是說同一個線程對象,不能兩次重復調用start()方法,否則就會拋出異常。
  • 線程啟動之后就會被加入到一個線程組中,后續會說到線程組相關的概念。
  • 當一個線程結束,進入到TERMINATED狀態之后,是沒有辦法通過調用start()方法再次進入到RUNNABLE狀態或者是RUNNING狀態的。

模板設計模式在Thread中的使用

通過上面的分析,可以知道,一個線程真正的邏輯執行代碼是被放到run()方法中,通常情況下run()方法就是我們編寫線程執行邏輯的地方,這也就是為什么我們要重寫run()方法,用start()啟動的線程。Thread類中的run方法如下。

@Override public void run() { if (target != null) { target.run(); } }

默認情況下,這個方法可以看做是一個空方法。方法體中沒有任何代碼。

不難發現在Thread中的run()方法start()方法就是一個非常典型的模板設計模式,父類編寫算法結構代碼,子類負責按照對應的模板進行實現。下面來看一個小例子

模板設計模式小例子

首先創建一個消息輸出的接口類,這個類就是制定消息輸出的規則,代碼如下

public interface PrintMessage { abstract void print();}

接下來就是其子類要實現這個消息輸出消息了。代碼如下

public class Repoter implements PrintMessage { public void printNews() { print(); } @Override public void print() { System.out.println("show news"); }}

編寫測試類main方法。

public class TemplateMain { public static void main(String[] args) { Repoter repoter = new Repoter(){ @Override public void print() { System.out.println("這個是一個設計模板方法"); } }; repoter.printNews(); }}

這里會看到整個的模式都是按照Thread的模式來進行。其中的print()方法和printNews()方法就類似于Thread類的run()方法和start()方法。這樣一來,父類只需要告訴子類需要做的事情是什么,而不需要知道至于子類如何實現,最終就是子類的事情了。

簡單的模擬一個叫號系統

很多人都有過存款或者買票的體驗,他們有一個共同的特點就是需要排隊叫號。其實這種機制解決了很多的問題。例如可以做到限流,可以合理的分配處理人員的位置,可以很好的解決了由于排隊引起的社會矛盾。同時也減輕了業務員、管理人員的壓力

我們這里簡單的模擬有四個窗口的叫號系統。四個窗口就相當于有四個線程。通過這四個窗口來模擬50人排隊的場景。

public class TicketWindow extends Thread { private final String name; private static final int MAX = 50; private int index = 1; public TicketWindow(String name) { this.name = name; } @Override public void run() { while (index<max){ system.out.println(name+"="" 號柜臺,出號="" "+index++);="" }="" public="" static="" void="" main(string[]="" args){="" ticketwindow="" ticketwindow1="new" ticketwindow("一");="" ticketwindow1.start();="" ticketwindow2="new" ticketwindow("二");="" ticketwindow2.start();="" ticketwindow3="new" ticketwindow("三");="" ticketwindow3.start();="" ticketwindow4="new" ticketwindow("四");="" ticketwindow4.start();="" }}

運行上面代碼之后會看到如下的結果,簡單地分析之后,會發現其實這是有問題的。1號票被多個柜臺出了。

為什么會出現這樣的問題,這就是每個線程執行的邏輯都不一樣,新建了四個線程,每個線程的票號都是從0~50。四個線程并沒有操作同一個票號排序。所以就會出現上面這個問題。那么我們如何去解決這個問題呢?我們想到了使用static 去修飾 index變量的方式。代碼如下。

public class TicketWindow extends Thread { private final String name; private static final int MAX = 50; private static int index = 1; public TicketWindow(String name) { this.name = name; } @Override public void run() { while (index<max){ system.out.println(name+"="" 號柜臺,出號="" "+index++);="" }="" public="" static="" void="" main(string[]="" args){="" ticketwindow="" ticketwindow1="new" ticketwindow("一");="" ticketwindow1.start();="" ticketwindow2="new" ticketwindow("二");="" ticketwindow2.start();="" ticketwindow3="new" ticketwindow("三");="" ticketwindow3.start();="" ticketwindow4="new" ticketwindow("四");="" ticketwindow4.start();="" }}

經過修改之后,運行結果如下,這個時候看上去一切都就正常了。

通過對index進行static的修飾,做到了多線程共享索引的操作。看上去是滿足了需求,但是實際上還是有很多的問題,如果共享索引的數據太大的時候,也會出現線程安全的問題。這個問題在后續的分享中會提到。所以說static只能解決小問題,需要解決大問題的話還需要大手筆的解決方案。在后續的分享中也會提到。這里就先到這里,大家可以先消化一下Thread 的模板設計模式原理。

總結

以上是生活随笔為你收集整理的Java高并发编程-剖析线程启动的start方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。