1. 程式人生 > 其它 >LeetCode-238-除自身以外陣列的乘積

LeetCode-238-除自身以外陣列的乘積

  學習java很久很久了,得有個5年了,但是從來都沒有真正的走進java世界,希望從這篇文章開始,把自己對java的點點滴滴都記錄下來。

  從java5開始,java就提供了名叫Executor framework的機制,主要是圍繞著Executor介面, 它的介面 ExecutorService, 以及實現了這兩個介面的ThreadPoolExecutor類來展開,這種機制把執行緒的執行和建立分離開了,你只需要建立一個執行緒,然後把執行緒丟給Executor,讓它執行去吧。使用這個機制的另外一個好處是可以使用Callable介面,它類似於Runnable介面,但是有兩個不一樣的特性。

  • 它的主要方法是call(), 它可以攜帶一個返回值。
  • 當你傳送了一個Callable物件給executor之後,你可以拿到一個實現了Future介面的物件,通過這個物件,你可以控制物件的狀態以及Callable物件的結果。
public Server(){
executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(5);
System.out.printf("Server: Task Count: %dn",executor.
getTaskCount());
} 

    提交帶返回值的任務。
public class FactorialCalculator implements Callable<Integer> {
    private Integer number;
public FactorialCalculator(Integer number){
this.number=number;
}
@Override
public Integer call() throws Exception {
    int result = 1;
if ((num==0)||(num==1)) {
result=1;
} else {
for (int i=2; i<=number; i++) {
result*=i;
TimeUnit.MILLISECONDS.sleep(20);
}
}
System.out.printf("%s: %dn",Thread.currentThread().
getName(),result);
return result;
}

public class Main {
public static void main(String[] args) {
    ThreadPoolExecutor executor=(ThreadPoolExecutor)Executors.
newFixedThreadPool(2);
List<Future<Integer>> resultList=new ArrayList<>();
Random random=new Random();
for (int i=0; i<10; i++){
Integer number= random.nextInt(10);
FactorialCalculator calculator=new 
FactorialCalculator(number);
Future<Integer> result=executor.submit(calculator);
resultList.add(result);
}
do {
    for (int i=0; i<resultList.size(); i++) {
Future<Integer> result=resultList.get(i);
System.out.printf("Main: Task %d: %sn",i,result.
isDone());
}
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (executor.getCompletedTaskCount()<resultList.size());
System.out.printf("Main: Resultsn");
for (int i=0; i<resultList.size(); i++) {
Future<Integer> result=resultList.get(i);
Integer number=null;
try {
number=result.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.printf("Main: Task %d: %dn",i,number);
}
executor.shutdown();
}
}

}

  在Future物件裡面,我們可以通過result.isDone()方法來判斷執行緒是否計算完畢。

   執行一堆任務,只返回第一個完成的任務。result = executor.invokeAny(taskList);

  執行全部,resultList=executor.invokeAll(taskList);

  推遲執行,executor.awaitTermination(1, TimeUnit.DAYS);

  把任務的執行和結果的處理分開,需要用到CompletionService, CompletionServicei有兩個方法,take和poll,poll是如果沒有,它就會立刻返回一個null,take是沒有的話,會一直等待。

  當執行緒池呼叫了關閉之後,它需要等待當前所有進行中的執行緒結束才會完全關閉,在這個過程當中提交的執行緒,需要拒絕處理,我們需要實現一個RejectedExecutionHandler,重寫它的rejectedExecution方法,然後聽過executor的setRejectedExecutionHandler()方法來設定。

public class RejectedTaskController implements 
RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor 
executor) {
System.out.printf("RejectedTaskController: The task %s has 
been rejectedn",r.toString());
System.out.printf("RejectedTaskController: %sn",executor.
toString());
System.out.printf("RejectedTaskController: Terminating: 
%sn",executor.isTerminating());
System.out.printf("RejectedTaksController: Terminated: 
%sn",executor.isTerminated());
}

Fork/Join Framework

     Fork/Join Framwork的誕生是為了解決如下圖這樣的問題的

     我們可以利用ForkJoinPool,它是一個特殊的Executors。

         ForkJoin 框架主要是有兩個操作:

         Fork:把一個任務分成幾個小任務,然後執行

         Join:等待小任務的完成,並生成一個新任務。

         這裡我把ForkJoin稱為刀叉框架,刀叉框架和Executor框架不一樣的地方在於work-stealing演算法,不同於Executor框架,刀叉框架在等待子任務的完成之前就已經建立並開始執行Join方法,Join方法一直在檢測任務是否完成並且開始執行。通過這樣的方式,可以很好的利用runtime的優勢,提高效能。

         這樣就有一些限制:

         任務只能採用Fork和Join來作為同步機制,而不能採用別的同步機制,如果採用其他的機制,他們在同步操作的時候,不能執行別的任務。比如:當你在刀叉框架裡面一個任務sleep的時候,別的正在執行的任務也會停止,直到該執行緒sleep結束。

         刀叉框架的核心是兩個類:

(1)ForkJoinPool,它實現了ExecutorService介面和work-stealing演算法,通過它可以很好的管理正在執行的任務以及瞭解任務的資訊。

(2)ForkJoinTask,任務的基類,它提供了fork()方法和join()方法來控制任務的狀態。不同通常,你會實現他們的兩個子類,不帶返回結果的RecursiveAction和帶返回結果的RecursiveTask。