2014-09-30 111 views
0

我有問題。如何在Java代碼中啓動一組線程

我有10000個字符串,我想對他們每個人執行一些操作。我想將這些操作並行化,以使總執行時間可以接受。

我決定創建線程。特別是,我每10個字符串就會啓動10個線程。對於每個線程,我將結果保存在列表中。

我試過兩個版本的代碼。這是我的第一個版本。

int size = 10000; 
int cont = 0; 
     int n = 1; 
     String[] arrstr2; 
     int threadgroup = 10; 
if (cont + threadgroup - 1 > size) { 
         arrstr2[i - cont] = subject.toString(); 
        } else { 
         arrstr2[i - cont] = subject.toString(); 
        } 

        if ((i == (threadgroup * n) - 1) || (i == size - 1)) { 

         cont = i + 1; 
         n = n + 1; 
         for (int j = 0; j < arrstr2.length; j++) { 
          Thread t = new Thread(new MyThread(arrstr2[j], l)); 
          t.start(); 

          try { 
           t.join(); 
          } catch (InterruptedException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
          } 
         } 
         if (cont + threadgroup - 1 > size) { 
          arrstr2 = new String[size - i - 1]; 
         } 
        } 
        i = i + 1; 

在這個版本中,我沒有得到總執行的優勢。

這是我的第二個版本:

int size = 10000; 
    int cont = 0; 
      int n = 1; 
      String[] arrstr2; 
      int threadgroup = 10; 
    if (cont + threadgroup - 1 > size) { 
          arrstr2[i - cont] = subject.toString(); 
         } else { 
          arrstr2[i - cont] = subject.toString(); 
         } 

         if ((i == (threadgroup * n) - 1) || (i == size - 1)) { 

          cont = i + 1; 
          n = n + 1; 
          for (int j = 0; j < arrstr2.length; j++) { 
           Thread t = new Thread(new MyThread(arrstr2[j], l)); 
           t.start(); 

          } 
try { 
           Thread.sleep(500); 
          } catch (InterruptedException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
          } 
          if (cont + threadgroup - 1 > size) { 
           arrstr2 = new String[size - i - 1]; 
          } 
         } 
         i = i + 1; 

在這種情況下,我失去了一些信息。 MyThread的是,做了一些處理,並提出在列表中的Java結果的類:

public class MyThread implements Runnable{ 

    String subject; 
    private List<String[]> l; 

    public MyThread(String subject, List<String[]> l) { 
     this.subject = subject; 
     this.l = l; 
    } 

    @Override 
    public void run() { 

     synchronized (l){ 
     //do something 
     String[] result = new String[2]; 
     result[0] = res0; 
     result[1] = res1; 
     l.add(result); 
    } 
} 

對於我的目標,這個代碼是正確的嗎?如何在Java代碼中啓動一組線程並檢索可接受的時間?

+3

使用的ExecutorService的一個固定的線程池! :) – 2014-09-30 12:33:50

+0

你能爲我做一個例子嗎? – Musich87 2014-09-30 12:34:58

+0

看看這裏:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html – PeterMmm 2014-09-30 12:35:00

回答

1

下面是一個ExecutorService的小示例。線程大小固定爲10,但您可以根據需要進行調整。

StringTask基本上顛倒了給定的字符串。

public class Test { 

    private static final int THREADS = 10; 
    private static final int DATA_SIZE = 1000; 

    public static void main(String[] args) { 
     // Declare a new ExecutorService with a maximum of 2 threads. 
     ExecutorService service = Executors.newFixedThreadPool(THREADS); 

     // Prepare a list of Future results. 
     List<Future<String>> futures = new ArrayList<Future<String>>(DATA_SIZE); 

     // Submit the tasks and store the results. 
     for (int i = 0; i < DATA_SIZE; i++) { 
      futures.add(service.submit(new StringTask("Sample String " + i))); 
     } 

     // Accept no new tasks. 
     service.shutdown(); 

     // Retrieve the actual String results. 
     List<String> results = new ArrayList<String>(DATA_SIZE); 
     try { 
      for (Future<String> future : futures) { 
       // The get() method blocks if the execution of the task is not finished. 
       results.add(future.get()); 
       System.out.println(future.get()); 
      } 
     } catch (ExecutionException ee) { 
      System.out.println("Error while getting result!"); 
      ee.printStackTrace(); 
     } catch (InterruptedException ie) { 
      System.out.println("Error while getting result!"); 
      ie.printStackTrace(); 
     } 
    } 

    /** 
    * Callable task that reverses a given String. 
    */ 
    private static final class StringTask implements Callable<String> { 
     private String input; 

     private StringTask(String input) { 
      super(); 

      if (input == null) { 
       throw new NullPointerException(); 
      } 

      this.input = input; 
     } 

     @Override 
     public String call() throws Exception { 
      StringBuilder builder = new StringBuilder(); 

      for (int i = this.input.length() - 1; i >= 0; i--) { 
       builder.append(this.input.charAt(i)); 
      } 

      return builder.toString(); 
     } 
    } 
} 

我使用Callable這裏,而不是Runnable因爲Callable允許作業實際回報,我們可以使用(通過Future接口)的結果。如果您只需要執行任務,則可以簡單地使用Runnable

+0

這個解決方案很好,但在我的情況下,我得到一個錯誤。我的線程必須執行的操作主要關注SPARQL查詢的執行(爲簡潔起見,我以前省略)。特別是我有QueryExecution exec1 = querymy(stringa,stringa1); ResultSet results1 = ResultSetFactory.copyResults(exec1.execSelect()); 我看到線程正確啓動,但是當我檢索結果時, – Musich87 2014-09-30 14:11:41

+0

我收到此錯誤: 獲取結果時出現錯誤! java.util.concurrent.ExecutionException:HttpException:503 \t在java.util.concurrent.FutureTask.report(FutureTask.java:122) \t在java.util.concurrent.FutureTask.get(FutureTask.java:188) 。特別是,我在循環中得到這個錯誤:for(Future future:futures){//如果任務執行沒有完成,則get()方法會被阻止。 results.add(future.get()); System.out.println(future.get()); } – Musich87 2014-09-30 14:12:10

+0

@ Musich87 [ExecutionException](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutionException.html)doc表示在嘗試檢索時發生此異常_thrown拋出異常而中止的任務的結果。SPARQL查詢的執行是否會引發異常?也許'Throwable.getCause()'可以幫助你做到這一點。 – 2014-09-30 14:24:02

0

使用Java 8:

List<String> res = Arrays.toStream(arrstr2) 
         .parallel() 
         .map(s -> doWork(s)) 
         .collect(Collectors.toList()); 
+0

s是我的字符串,對吧?誰是收藏家? – Musich87 2014-09-30 15:59:06

+0

我在哪裏可以下載適用於64位的Java 8 EE? – Musich87 2014-09-30 16:07:34

+0

這裏:https://www.google.com/search?q=jdk8但也許你應該堅持使用java 7,並使用ExecutorService作爲Alexis Leclerc的建議。 – 2014-09-30 16:09:13