成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

JDK 7中的 Fork/Join模式

開發 后端
對Fork/Join 模式的支持可能是對開發并行軟件來說最通用的新特性。在 JSR-166y 中,Doug Lea 實現ArrayTasks/ListTasks/IntTasks/LongTasks/DoubleTasks 時就大量的用到了 Fork/Join 模式。讀者還需要注意一點,因為 JDK 7 還沒有正式發布,因此本文涉及到的功能和發布版本有可能不一樣。

介  紹

隨著多核芯片逐漸成為主流,大多數軟件開發人員不可避免地需要了解并行編程的知識。而同時,主流程序語言正在將越來越多的并行特性合并到標準庫或者語言本身之中。我們可以看到,JDK 在這方面同樣走在潮流的前方。在 JDK 標準版 5 中,由 Doug Lea 提供的并行框架成為了標準庫的一部分(JSR-166)。隨后,在 JDK 6 中,一些新的并行特性,例如并行 collection 框架,合并到了標準庫中(JSR-166x)。直到今天,盡管 Java SE 7 還沒有正式發布,一些并行相關的新特性已經出現在 JSR-166y 中:

1.Fork/Join 模式;

2.TransferQueue,它繼承自 BlockingQueue 并能在隊列滿時阻塞“生產者”;

3.ArrayTasks/ListTasks,用于并行執行某些數組/列表相關任務的類;

4.IntTasks/LongTasks/DoubleTasks,用于并行處理數字類型數組的工具類,提供了排序、查找、求和、求最小值、求最大值等功能;

其中,對 Fork/Join 模式的支持可能是對開發并行軟件來說最通用的新特性。在 JSR-166y 中,Doug Lea 實現ArrayTasks/ListTasks/IntTasks/LongTasks/DoubleTasks 時就大量的用到了 Fork/Join 模式。讀者還需要注意一點,因為 JDK 7 還沒有正式發布,因此本文涉及到的功能和發布版本有可能不一樣。

Fork/Join 模式有自己的適用范圍。如果一個應用能被分解成多個子任務,并且組合多個子任務的結果就能夠獲得最終的答案,那么這個應用就適合用 Fork/Join 模式來解決。圖 1 給出了一個 Fork/Join 模式的示意圖,位于圖上部的 Task 依賴于位于其下的 Task 的執行,只有當所有的子任務都完成之后,調用者才能獲得 Task 0 的返回結果。

圖 1. Fork/Join 模式示意圖

可以說,Fork/Join 模式能夠解決很多種類的并行問題。通過使用 Doug Lea 提供的 Fork/Join 框架,軟件開發人員只需要關注任務的劃分和中間結果的組合就能充分利用并行平臺的優良性能。其他和并行相關的諸多難于處理的問題,例如負載平衡、同步等,都可以由框架采用統一的方式解決。這樣,我們就能夠輕松地獲得并行的好處而避免了并行編程的困難且容易出錯的缺點。

使用 Fork/Join 模式

在開始嘗試 Fork/Join 模式之前,我們需要從 Doug Lea 主持的 Concurrency JSR-166 Interest Site 上下載 JSR-166y 的源代碼,并且我們還需要安裝最新版本的 JDK 6(下載網址請參閱 參考資源)。Fork/Join 模式的使用方式非常直觀。首先,我們需要編寫一個 ForkJoinTask 來完成子任務的分割、中間結果的合并等工作。隨后,我們將這個 ForkJoinTask 交給 ForkJoinPool 來完成應用的執行。

通常我們并不直接繼承 ForkJoinTask,它包含了太多的抽象方法。針對特定的問題,我們可以選擇 ForkJoinTask 的不同子類來完成任務。RecursiveAction 是 ForkJoinTask 的一個子類,它代表了一類最簡單的 ForkJoinTask:不需要返回值,當子任務都執行完畢之后,不需要進行中間結果的組合。如果我們從 RecursiveAction 開始繼承,那么我們只需要重載 protected void compute() 方法。下面,我們來看看怎么為快速排序算法建立一個 ForkJoinTask 的子類:

清單 1. ForkJoinTask 的子類

  1. classSortTaskextendsRecursiveAction{  
  2. finallong[]array;  
  3. finalintlo;  
  4. finalinthi;  
  5. privateintTHRESHOLD=30;  
  6.  
  7. publicSortTask(long[]array){  
  8. this.array=array;  
  9. this.lo=0;  
  10. this.hi=array.length-1;  
  11. }  
  12.  
  13. publicSortTask(long[]array,intlo,inthi){  
  14. this.array=array;  
  15. this.lo=lo;  
  16. this.hi=hi;  
  17. }  
  18.  
  19. protectedvoidcompute(){  
  20. if(hi-lo<THRESHOLD)  
  21. sequentiallySort(array,lo,hi);  
  22. else{  
  23. intpivot=partition(array,lo,hi);  
  24. coInvoke(newSortTask(array,lo,pivot-1),newSortTask(array,  
  25. pivot+1,hi));  
  26. }  
  27. }  
  28.  
  29. privateintpartition(long[]array,intlo,inthi){  
  30. longx=array[hi];  
  31. inti=lo-1;  
  32. for(intj=lo;j<hi;j++){  
  33. if(array[j]<=x){  
  34. i++;  
  35. swap(array,i,j);  
  36. }  
  37. }  
  38. swap(array,i+1,hi);  
  39. returni+1;  
  40. }  
  41.  
  42. privatevoidswap(long[]array,inti,intj){  
  43. if(i!=j){  
  44. longtemp=array[i];  
  45. array[i]=array[j];  
  46. array[j]=temp;  
  47. }  
  48. }  
  49.  
  50. privatevoidsequentiallySort(long[]array,intlo,inthi){  
  51. Arrays.sort(array,lo,hi+1);  
  52. }  

在清單1中,SortTask 首先通過 partition() 方法將數組分成兩個部分。隨后,兩個子任務將被生成并分別排序數組的兩個部分。當子任務足夠小時,再將其分割為更小的任務反而引起性能的降低。因此,這里我們使用一個 THRESHOLD,限定在子任務規模較小時,使用直接排序,而不是再將其分割成為更小的任務。其中,我們用到了 RecursiveAction 提供的方法 coInvoke()。它表示:啟動所有的任務,并在所有任務都正常結束后返回。如果其中一個任務出現異常,則其它所有的任務都取消。coInvoke() 的參數還可以是任務的數組。

現在剩下的工作就是將 SortTask 提交到 ForkJoinPool 了。ForkJoinPool() 默認建立具有與 CPU 可使用線程數相等線程個數的線程池。我們在一個 JUnit 的 test 方法中將 SortTask 提交給一個新建的 ForkJoinPool:

清單 2. 新建的 ForkJoinPool

  1. @Test 
  2. publicvoidtestSort()throwsException{  
  3. ForkJoinTasksort=newSortTask(array);  
  4. ForkJoinPoolfjpool=newForkJoinPool();  
  5. fjpool.submit(sort);  
  6. fjpool.shutdown();  
  7.  
  8. fjpool.awaitTermination(30,TimeUnit.SECONDS);  
  9.  
  10. assertTrue(checkSorted(array));  
  11. }  

在上面的代碼中,我們用到了 ForkJoinPool 提供的如下函數:

1. submit():將 ForkJoinTask 類的對象提交給 ForkJoinPool,ForkJoinPool 將立刻開始執行 ForkJoinTask。

2. shutdown():執行此方法之后,ForkJoinPool 不再接受新的任務,但是已經提交的任務可以繼續執行。如果希望立刻停止所有的任務,可以嘗試 shutdownNow() 方法。

3. awaitTermination():阻塞當前線程直到 ForkJoinPool 中所有的任務都執行結束。

并行快速排序的完整代碼如下所示:

清單 3. 并行快速排序的完整代碼

  1. packagetests;  
  2. importstaticorg.junit.Assert.*;  
  3. importjava.util.Arrays;  
  4. importjava.util.Random;  
  5. importjava.util.concurrent.TimeUnit;  
  6. importjsr166y.forkjoin.ForkJoinPool;  
  7. importjsr166y.forkjoin.ForkJoinTask;  
  8. importjsr166y.forkjoin.RecursiveAction;  
  9. importorg.junit.Before;  
  10. importorg.junit.Test;  
  11. classSortTaskextendsRecursiveAction{  
  12. finallong[]array;  
  13. finalintlo;  
  14. finalinthi;  
  15. privateintTHRESHOLD=0;//Fordemoonly  
  16. publicSortTask(long[]array){  
  17. this.array=array;  
  18. this.lo=0;  
  19. this.hi=array.length-1;  
  20. }  
  21. publicSortTask(long[]array,intlo,inthi){  
  22. this.array=array;  
  23. this.lo=lo;  
  24. this.hi=hi;  
  25. }  
  26. protectedvoidcompute(){  
  27. if(hi-lo<THRESHOLD)  
  28. sequentiallySort(array,lo,hi);  
  29. else{  
  30. intpivot=partition(array,lo,hi);  
  31. System.out.println(" pivot="+pivot+",low="+lo+",high="+hi);  
  32. System.out.println("array"+Arrays.toString(array));  
  33. coInvoke(newSortTask(array,lo,pivot-1),newSortTask(array,  
  34. pivot+1,hi));  
  35. }  
  36. }  
  37. privateintpartition(long[]array,intlo,inthi){  
  38. longx=array[hi];  
  39. inti=lo-1;  
  40. for(intj=lo;j<hi;j++){  
  41. if(array[j]<=x){  
  42. i++;  
  43. swap(array,i,j);  
  44. }  
  45. }  
  46. swap(array,i+1,hi);  
  47. returni+1;  
  48. }  
  49. privatevoidswap(long[]array,inti,intj){  
  50. if(i!=j){  
  51. longtemp=array[i];  
  52. array[i]=array[j];  
  53. array[j]=temp;  
  54. }  
  55. }  
  56. privatevoidsequentiallySort(long[]array,intlo,inthi){  
  57. Arrays.sort(array,lo,hi+1);  
  58. }  
  59. }  
  60. publicclassTestForkJoinSimple{  
  61. privatestaticfinalintNARRAY=16;//Fordemoonly  
  62. long[]array=newlong[NARRAY];  
  63. Randomrand=newRandom();  
  64. @Before 
  65. publicvoidsetUp(){  
  66. for(inti=0;i<array.length;i++){  
  67. array[i]=rand.nextLong()%100;//Fordemoonly  
  68. }  
  69. System.out.println("InitialArray:"+Arrays.toString(array));  
  70. }  
  71. @Test 
  72. publicvoidtestSort()throwsException{  
  73. ForkJoinTasksort=newSortTask(array);  
  74. ForkJoinPoolfjpool=newForkJoinPool();  
  75. fjpool.submit(sort);  
  76. fjpool.shutdown();  
  77. fjpool.awaitTermination(30,TimeUnit.SECONDS);  
  78. assertTrue(checkSorted(array));  
  79. }  
  80. booleancheckSorted(long[]a){  
  81. for(inti=0;i<a.length-1;i++){  
  82. if(a[i]>(a[i+1])){  
  83. returnfalse;  
  84. }  
  85. }  
  86. returntrue;  
  87. }  
  88. }  

運行以上代碼,我們可以得到以下結果:

  1. InitialArray:[46,-12,74,-67,76,-13,-91,-96]  
  2.  
  3. pivot=0,low=0,high=7 
  4. array[-96,-12,74,-67,76,-13,-91,46]  
  5.  
  6. pivot=5,low=1,high=7 
  7. array[-96,-12,-67,-13,-91,46,76,74]  
  8.  
  9. pivot=1,low=1,high=4 
  10. array[-96,-91,-67,-13,-12,46,74,76]  
  11.  
  12. pivot=4,low=2,high=4 
  13. array[-96,-91,-67,-13,-12,46,74,76]  
  14.  
  15. pivot=3,low=2,high=3 
  16. array[-96,-91,-67,-13,-12,46,74,76]  
  17.  
  18. pivot=2,low=2,high=2 
  19. array[-96,-91,-67,-13,-12,46,74,76]  
  20.  
  21. pivot=6,low=6,high=7 
  22. array[-96,-91,-67,-13,-12,46,74,76]  
  23.  
  24. pivot=7,low=7,high=7 
  25. array[-96,-91,-67,-13,-12,46,74,76]  

#p#

Fork/Join 模式高級特性

使用 RecursiveTask

除了 RecursiveAction,Fork/Join 框架還提供了其他 ForkJoinTask 子類:帶有返回值的 RecursiveTask,使用 finish() 方法顯式中止的 AsyncAction 和 LinkedAsyncAction,以及可使用 TaskBarrier 為每個任務設置不同中止條件的 CyclicAction。

從 RecursiveTask 繼承的子類同樣需要重載 protected void compute() 方法。與 RecursiveAction 稍有不同的是,它可使用泛型指定一個返回值的類型。下面,我們來看看如何使用 RecursiveTask 的子類。

清單 4. RecursiveTask 的子類

  1. classFibonacciextendsRecursiveTask<Integer>{  
  2. finalintn;  
  3.  
  4. Fibonacci(intn){  
  5. this.n=n;  
  6. }  
  7.  
  8. privateintcompute(intsmall){  
  9. finalint[]results={1,1,2,3,5,8,13,21,34,55,89};  
  10. returnresults[small];  
  11. }  
  12.  
  13. publicIntegercompute(){  
  14. if(n<=10){  
  15. returncompute(n);  
  16. }  
  17. Fibonaccif1=newFibonacci(n-1);  
  18. Fibonaccif2=newFibonacci(n-2);  
  19. f1.fork();  
  20. f2.fork();  
  21. returnf1.join()+f2.join();  
  22. }  

在清單4 中,Fibonacci 的返回值為 Integer 類型。其 compute() 函數首先建立兩個子任務,啟動子任務執行,阻塞以等待子任務的結果返回,相加后得到最終結果。同樣,當子任務足夠小時,通過查表得到其結果,以減小因過多地分割任務引起的性能降低。其中,我們用到了 RecursiveTask 提供的方法 fork() 和 join()。它們分別表示:子任務的異步執行和阻塞等待結果完成。

現在剩下的工作就是將 Fibonacci 提交到 ForkJoinPool 了,我們在一個 JUnit 的 test 方法中作了如下處理:

清單 5. 將 Fibonacci 提交到 ForkJoinPool

  1. @Test 
  2. publicvoidtestFibonacci()throwsInterruptedException,ExecutionException{  
  3. ForkJoinTask<Integer>fjt=newFibonacci(45);  
  4. ForkJoinPoolfjpool=newForkJoinPool();  
  5. Future<Integer>result=fjpool.submit(fjt);  
  6.  
  7. //dosomething  
  8. System.out.println(result.get());  
  9. }  

使用 CyclicAction 來處理循環任務

CyclicAction 的用法稍微復雜一些。如果一個復雜任務需要幾個線程協作完成,并且線程之間需要在某個點等待所有其他線程到達,那么我們就能方便的用 CyclicAction 和 TaskBarrier 來完成。圖 2 描述了使用 CyclicAction 和 TaskBarrier 的一個典型場景。

圖 2. 使用 CyclicAction 和 TaskBarrier 執行多線程任務

繼承自 CyclicAction 的子類需要 TaskBarrier 為每個任務設置不同的中止條件。從 CyclicAction 繼承的子類需要重載 protected void compute() 方法,定義在 barrier 的每個步驟需要執行的動作。compute() 方法將被反復執行直到 barrier 的 isTerminated() 方法返回 True。TaskBarrier 的行為類似于 CyclicBarrier。下面,我們來看看如何使用 CyclicAction 的子類。

清單 6. 使用 CyclicAction 的子類

  1. classConcurrentPrintextendsRecursiveAction{  
  2. protectedvoidcompute(){  
  3. TaskBarrierb=newTaskBarrier(){  
  4. protectedbooleanterminate(intcycle,intregisteredParties){  
  5. System.out.println("Cycleis"+cycle+";" 
  6. +registeredParties+"parties");  
  7. returncycle>=10;  
  8. }  
  9. };  
  10. intn=3;  
  11. CyclicAction[]actions=newCyclicAction[n];  
  12. for(inti=0;i<n;++i){  
  13. finalintindex=i;  
  14. actions[i]=newCyclicAction(b){  
  15. protectedvoidcompute(){  
  16. System.out.println("I'mworking"+getCycle()+"" 
  17. +index);  
  18. try{  
  19. Thread.sleep(500);  
  20. }catch(InterruptedExceptione){  
  21. e.printStackTrace();  
  22. }  
  23. }  
  24. };  
  25. }  
  26. for(inti=0;i<n;++i)  
  27. actions[i].fork();  
  28. for(inti=0;i<n;++i)  
  29. actions[i].join();  
  30. }  
  31. }  

在清單6中,CyclicAction[] 數組建立了三個任務,打印各自的工作次數和序號。而在 b.terminate() 方法中,我們設置的中止條件表示重復 10 次計算后中止。現在剩下的工作就是將 ConcurrentPrint 提交到 ForkJoinPool 了。我們可以在 ForkJoinPool 的構造函數中指定需要的線程數目,例如 ForkJoinPool(4) 就表明線程池包含 4 個線程。我們在一個 JUnit 的 test 方法中運行 ConcurrentPrint 的這個循環任務:

清單 7. 運行 ConcurrentPrint 循環任務

  1. @Test 
  2. publicvoidtestBarrier()throwsInterruptedException,ExecutionException{  
  3. ForkJoinTaskfjt=newConcurrentPrint();  
  4. ForkJoinPoolfjpool=newForkJoinPool(4);  
  5. fjpool.submit(fjt);  
  6. fjpool.shutdown();  

RecursiveTask 和 CyclicAction 兩個例子的完整代碼如下所示:

清單 8. RecursiveTask 和 CyclicAction 兩個例子的完整代碼

  1. packagetests;  
  2.  
  3. importjava.util.concurrent.ExecutionException;  
  4. importjava.util.concurrent.Future;  
  5.  
  6. importjsr166y.forkjoin.CyclicAction;  
  7. importjsr166y.forkjoin.ForkJoinPool;  
  8. importjsr166y.forkjoin.ForkJoinTask;  
  9. importjsr166y.forkjoin.RecursiveAction;  
  10. importjsr166y.forkjoin.RecursiveTask;  
  11. importjsr166y.forkjoin.TaskBarrier;  
  12.  
  13. importorg.junit.Test;  
  14.  
  15. classFibonacciextendsRecursiveTask<Integer>{  
  16. finalintn;  
  17.  
  18. Fibonacci(intn){  
  19. this.n=n;  
  20. }  
  21.  
  22. privateintcompute(intsmall){  
  23. finalint[]results={1,1,2,3,5,8,13,21,34,55,89};  
  24. returnresults[small];  
  25. }  
  26.  
  27. publicIntegercompute(){  
  28. if(n<=10){  
  29. returncompute(n);  
  30. }  
  31. Fibonaccif1=newFibonacci(n-1);  
  32. Fibonaccif2=newFibonacci(n-2);  
  33. System.out.println("forknewthreadfor"+(n-1));  
  34. f1.fork();  
  35. System.out.println("forknewthreadfor"+(n-2));  
  36. f2.fork();  
  37. returnf1.join()+f2.join();  
  38. }  
  39. }  
  40.  
  41. classConcurrentPrintextendsRecursiveAction{  
  42. protectedvoidcompute(){  
  43. TaskBarrierb=newTaskBarrier(){  
  44. protectedbooleanterminate(intcycle,intregisteredParties){  
  45. System.out.println("Cycleis"+cycle+";" 
  46. +registeredParties+"parties");  
  47. returncycle>=10;  
  48. }  
  49. };  
  50. intn=3;  
  51. CyclicAction[]actions=newCyclicAction[n];  
  52. for(inti=0;i<n;++i){  
  53. finalintindex=i;  
  54. actions[i]=newCyclicAction(b){  
  55. protectedvoidcompute(){  
  56. System.out.println("I'mworking"+getCycle()+"" 
  57. +index);  
  58. try{  
  59. Thread.sleep(500);  
  60. }catch(InterruptedExceptione){  
  61. e.printStackTrace();  
  62. }  
  63. }  
  64. };  
  65. }  
  66. for(inti=0;i<n;++i)  
  67. actions[i].fork();  
  68. for(inti=0;i<n;++i)  
  69. actions[i].join();  
  70. }  
  71. }  
  72.  
  73. publicclassTestForkJoin{  
  74. @Test 
  75. publicvoidtestBarrier()throwsInterruptedException,ExecutionException{  
  76. System.out.println(" testingTaskBarrier...");  
  77. ForkJoinTaskfjt=newConcurrentPrint();  
  78. ForkJoinPoolfjpool=newForkJoinPool(4);  
  79. fjpool.submit(fjt);  
  80. fjpool.shutdown();  
  81. }  
  82.  
  83. @Test 
  84. publicvoidtestFibonacci()throwsInterruptedException,ExecutionException{  
  85. System.out.println(" testingFibonacci...");  
  86. finalintnum=14;//Fordemoonly  
  87. ForkJoinTask<Integer>fjt=newFibonacci(num);  
  88. ForkJoinPoolfjpool=newForkJoinPool();  
  89. Future<Integer>result=fjpool.submit(fjt);  
  90.  
  91. //dosomething  
  92. System.out.println("Fibonacci("+num+")="+result.get());  
  93. }  
  94. }  

運行以上代碼,我們可以得到以下結果:

  1. testingTaskBarrier...  
  2. I'mworking02  
  3. I'mworking00  
  4. I'mworking01  
  5. Cycleis0;3parties  
  6. I'mworking12  
  7. I'mworking10  
  8. I'mworking11  
  9. Cycleis1;3parties  
  10. I'mworking20  
  11. I'mworking21  
  12. I'mworking22  
  13. Cycleis2;3parties  
  14. I'mworking30  
  15. I'mworking32  
  16. I'mworking31  
  17. Cycleis3;3parties  
  18. I'mworking42  
  19. I'mworking40  
  20. I'mworking41  
  21. Cycleis4;3parties  
  22. I'mworking51  
  23. I'mworking50  
  24. I'mworking52  
  25. Cycleis5;3parties  
  26. I'mworking60  
  27. I'mworking62  
  28. I'mworking61  
  29. Cycleis6;3parties  
  30. I'mworking72  
  31. I'mworking70  
  32. I'mworking71  
  33. Cycleis7;3parties  
  34. I'mworking81  
  35. I'mworking80  
  36. I'mworking82  
  37. Cycleis8;3parties  
  38. I'mworking90  
  39. I'mworking92  
  40.  
  41. testingFibonacci...  
  42. forknewthreadfor13  
  43. forknewthreadfor12  
  44. forknewthreadfor11  
  45. forknewthreadfor10  
  46. forknewthreadfor12  
  47. forknewthreadfor11  
  48. forknewthreadfor10  
  49. forknewthreadfor9  
  50. forknewthreadfor10  
  51. forknewthreadfor9  
  52. forknewthreadfor11  
  53. forknewthreadfor10  
  54. forknewthreadfor10  
  55. forknewthreadfor9  
  56. Fibonacci(14)=610  

結  論

從以上的例子中可以看到,通過使用 Fork/Join 模式,軟件開發人員能夠方便地利用多核平臺的計算能力。盡管還沒有做到對軟件開發人員完全透明,Fork/Join 模式已經極大地簡化了編寫并發程序的瑣碎工作。對于符合 Fork/Join 模式的應用,軟件開發人員不再需要處理各種并行相關事務,例如同步、通信等,以難以調試而聞名的死鎖和 data race 等錯誤也就不會出現,提升了思考問題的層次。你可以把 Fork/Join 模式看作并行版本的 Divide and Conquer 策略,僅僅關注如何劃分任務和組合中間結果,將剩下的事情丟給 Fork/Join 框架。

在實際工作中利用 Fork/Join 模式,可以充分享受多核平臺為應用帶來的免費午餐。

參考資料

◆  閱讀文章“The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software”:了解為什么從現在開始每個嚴肅的軟件工作者都應該了解并行編程方法。

◆ 閱讀 Doug Lea 的文章“A Java Fork/Join Framework”:了解 Fork/Join 模式的實現機制和執行性能。

◆ 閱讀 developerWorks 文章“馴服 Tiger:并發集合”:了解如何使用并行 Collection 庫。

◆ 閱讀 developerWorks 文章“Java 理論與實踐:非阻塞算法簡介”:介紹了 JDK 5 在并行方面的重要增強以及在 JDK5 平臺上如何實現非阻塞算法的一般介紹。

◆ 書籍“Java Concurrency in Practice”:介紹了大量的并行編程技巧、反模式、可行的解決方案等,它對于 JDK 5 中的新特性也有詳盡的介紹。

獲得產品和技術

訪問 Doug Lea 的 JSR 166 站點獲得最新的源代碼。

◆ 從 Sun 公司 網站下載 Java SE 6。

原文鏈接:http://zhangziyangup.iteye.com/blog/1324592

【編輯推薦】

  1. 利用JavaMail API 解析MIME
  2. 詳細解析Java中抽象類和接口的區別
  3. 解讀Java環境變量配置
  4. Java精確截取字符串
  5. Cinch和Sysmon發布 Java輔助開發工具

 

責任編輯:林師授 來源: zhangziyangup的博客
相關推薦

2011-05-20 10:15:06

JDK7

2017-08-04 11:41:53

Javathreadpool框架

2017-08-07 20:50:27

JavaForkJoin

2010-08-03 08:54:07

JDK 7Lambda表達式函數式編程

2017-01-13 15:45:05

Linuxfork函數詳解

2019-04-24 09:43:46

代碼開發工具

2020-05-08 10:48:49

forkjoinJava

2009-07-07 16:39:40

JDK Observe

2025-04-23 08:31:26

Java并發框架

2016-09-22 20:07:07

JavaScriptNode設計模式

2023-10-10 22:24:16

2010-04-01 13:09:12

Oracle中join

2021-08-11 21:46:47

MySQL索引join

2010-01-05 09:50:12

Windows7上帝模

2023-05-31 08:37:06

Java并發編程

2010-09-25 09:30:28

JDK 7Java 7

2010-07-29 10:20:35

JDK 7Java 7Java政治

2010-11-26 16:17:48

設計模式JDK

2012-05-30 15:25:22

JDKURLConnectiJava

2009-07-08 14:06:22

ClassLoaderJDK源碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 婷婷综合网 | 毛片免费看的 | 国产精品视频偷伦精品视频 | 成人二区| 国产精品久久久乱弄 | 国产午夜精品一区二区三区嫩草 | 亚洲成人久久久 | 国产精品视频免费播放 | 成人在线免费电影 | 国产亚洲成av人片在线观看桃 | 99re视频在线 | 欧美一级黄色片免费观看 | 精品视频一区二区 | 国产成人精品久久二区二区 | 久久精品国产99国产精品 | 精品一区国产 | 日日爱av| 国产一区二区三区久久 | 91免费观看在线 | 不卡一区二区在线观看 | 欧美成年网站 | 亚洲欧美日本在线 | 久久机热 | 国产精品美女一区二区三区 | 亚洲综合一区二区三区 | 少妇一级淫片免费放播放 | 一区二区福利视频 | 99re国产| 亚洲成网| 欧美高清一级片 | 久久精品国产一区二区电影 | 日韩一级二级片 | 色橹橹欧美在线观看视频高清 | 91手机精品视频 | 成年人网站在线观看视频 | 欧美激情国产精品 | 网色 | 久一精品 | 黄色片在线免费看 | .国产精品成人自产拍在线观看6 | 秋霞av国产精品一区 |