簡體   English   中英

Java中的線程處理技術

[英]Thread handling techniques in java

這是我的第一個專業線程應用程序,這讓我有些困惑。

我需要從API獲取大量數據,在該API中,我向三個不同的API端點提供了一個ID,並且我必須解析並處理這些數據,具體取決於哪個返回的是非null值。

我有一個有效的版本,但是沒有使用線程,並且花費很長時間才能完成。

主要思想是,我使用一個ID池,並試圖在一個循環內連接到API。 每個循環都創建一個新的Object,以處理連接和數據解析。

public void connect(){
    For(String id:idList){
      String url="...."+id;
      String reply=getData(url);
      if(reply!=null){
         //parse data
         parse(reply);
      } 
    }
}
public void parse(String data){
   //....
}

所以我想嘗試一下線程,以防線程加速。
到目前為止,我的嘗試似乎一直有效,我可以連接並下載數據,但是我還沒有弄清楚如何限制我創建的線程,以避免溢出或內存不足錯誤。
從我的研究中,我發現如果已經運行了太多線程,我可以讓新創建的線程進入睡眠狀態,例如:(例如,來自www.shayanderson.com的示例)

public class Test {
      public static final int MAX_THREADS = 3;
      public static int threads_counter = 0;

      public class MyThread extends Thread {
            String name;
            String says;
            private final int REPEATS = 1;
            private final int DELAY = 200;

            public MyThread(String in_name, String in_says) {
                  this.name = in_name;
                  this.says = in_says;
            }

            public void run() {
                  if(Test.threads_counter >= Test.MAX_THREADS) {
                        try {
                              Thread.sleep(this.DELAY);
                        } catch(Exception e) {
                              Test.addResponse("Thread error");
                        }
                        this.run();
                        return;
                  }

                  Test.threads_counter++;
                  try {
                        for(int i = 0; i < this.REPEATS; ++i) {
                              Test.addResponse(this.name + " says \"" + this.says + "\"");
                              Thread.sleep(this.DELAY);
                        }
                  } catch(Exception e) {
                        Test.addResponse("And error occured for Thread " + this.name);
                  } finally {
                        Test.addResponse("Thread " + this.name + " stopping");
                        Test.threads_counter--;
                  }
            }
      } 

我的嘗試看起來像這樣:

public void connect(){
    For(String id:idList){
      String url="...."+id;
      ThreadClass thread= new ThreadClas(url);
      Thread t = new Thread(thread);
       t.start();
    }
}
class ThreadClass implements Runnable{
   public final int MAX_THREADS = 10;
   public int threads_counter = 0; 

   public void run() {
       while(this.threads_counter >= this.MAX_THREADS){
          //sleep
        }
       threads_counter++;
       //fetch data and parse
       threads_counter--;
   }
}

但這是在創建線程並只是暫停它,所以我認為它會消耗RAM,就好像它在運行一樣,並考慮到我有好幾千個id,這肯定會給我帶來麻煩。
因此,如果我可以在主類中阻止線程的創建,那將更有意義。 我該怎么辦? 如果我使用計數器(如上例所示),則我不知道何時終止每個線程以開始創建新線程。
另一方面,我已經看到了wait()/notify()方法,但是由於我正在創建新的對象,因此我不確定如何實現它,因此無法一起通知它們。 我試圖閱讀有關並發性的Oracle Java教程,但這使我更加困惑。

更新 - (不是)解決方案
我確實設法使用池將類更改為線程運行(這對於任何有類似錯誤的人都是正確的方法),但是我遇到了連接問題(我正在使用jdbc-mySql連接和安全復制/ Jcraft連接),並且設置不正確。 在嘗試連接時,連接打開(和/或關閉)或打開的連接過多,因此出現異常。 我猜這是由於這樣的事實,當我編寫應用程序時,我是在方法內部打開和關閉這些連接,然后又變成一個線程,從而導致打開多個打開的連接。 現在這實在太麻煩了,因此我將改回單線程方法。

也許這對我來說應該是一個教訓,以面向線程的方式設計程序,並在需要時將其用作單個線程。

但這只是創建線程而只是暫停它,

實際上,它只是燃燒CPU。

所以我在想它會消耗掉RAM,就像它一直在運行一樣

它消耗CPU而不是RAM。

考慮到我有數千個ID,那肯定會給我帶來麻煩。

一旦您的線程數超過內核數(最有可能約為4個),就會引起問題。

因此,如果我可以在主類中阻止線程的創建,那將更有意義。 我該怎么辦?

如果您想限制活動線程的數量,我將使用一個隊列並將其傳遞給我,我還將使用一個線程池,例如固定大小的線程池。

如果我使用計數器(如上例所示),則我不知道何時終止每個線程以開始創建新線程。

您永遠不會,因為計數器不是線程保存的,而另一個線程可能永遠不會看到它的更新。

另一方面,我已經看到了wait()/ notify()方法,但是由於我正在創建新的對象,因此我不確定如何實現它,因此無法一起通知它們。

您可以向他們傳遞一個他們都可以看的對象,但是就像我說的那樣,固定大小的線程池Executor會簡單得多。

我試圖閱讀有關並發性的Oracle Java教程,但這使我更加困惑。

由於您要處理所有數據並收集結果,因此建議您使用parallelStream()。

public void connect(){
    List<String> results = idList.parallelStream()
                                 .map(id -> fetchDataAndParse(id))
                                 .collect(Collectors.toList());
}

我還沒有弄清楚如何限制我創建的線程。

這強烈表明您需要固定大小的線程 請參閱上方的Peter(+1)Lawry的答案。

我想嘗試一下線程,以防速度加快。

在任何程序中使用線程基本上有兩個原因:

1)在具有多個CPU的計算機上進行並行計算 (當我說“計算”時,它可能是數學運算,也可能是程序執行的幾乎所有其他操作,而該程序卻占用大量CPU時間而沒有做很多IO。)

2)簡化對由不同,獨立(或部分獨立)外部事件源驅動的不同抽象過程進行建模的程序的結構。

在單線程事件驅動程序,一個主事件循環具有接收和分類的所有不同種類的事件的,然后調用該驅動各種處理的處理程序 必須在處理程序調用之間持久存在的數據結構中明確編碼每個進程的狀態。 了解此類程序中發生的事情可能是一個挑戰。

在多線程程序中,每個抽象進程都可以由其自己的線程建模,並且該進程的許多狀態可以由線程的程序計數器和調用堆棧隱式表示。 與等效的事件驅動程序相比,多線程程序通常更易於閱讀 但是線程本身具有挑戰性,因此編寫正確的多線程程序本身就具有挑戰性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM