国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

Java 5.0多線程編程

2019-11-18 10:46:47
字體:
供稿:網(wǎng)友

    java自1995年面世以來得到了廣泛得一個運用,但是對多線程編程的支持Java很長時間一直停留在初級階段。在Java 5.0之前Java里的多線程編程主要是通過Thread類,Runnable接口,Object對象中的wait()、 notify()、 notifyAll()等方法和synchronized要害詞來實現(xiàn)的。這些工具雖然能在大多數(shù)情況下解決對共享資源的治理和線程間的調(diào)度,但存在以下幾個問題

1.      過于原始,拿來就能用的功能有限,即使是要實現(xiàn)簡單的多線程功能也需要編寫大量的代碼。這些工具就像匯編語言一樣難以學(xué)習(xí)和使用,比這更糟糕的是稍有不慎它們還可能被錯誤地使用,而且這樣的錯誤很難被發(fā)現(xiàn)。

2.      假如使用不當(dāng),會使程序的運行效率大大降低。

3.      為了提高開發(fā)效率,簡化編程,開發(fā)人員在做項目的時候往往需要寫一些共享的工具來實現(xiàn)一些普遍適用的功能。但因為沒有規(guī)范,相同的工具會被重復(fù)地開發(fā),造成資源浪費。

4.      因為鎖定的功能是通過Synchronized來實現(xiàn)的,這是一種塊結(jié)構(gòu),只能對代碼中的一段代碼進(jìn)行鎖定,而且鎖定是單一的。如以下代碼所示:

synchronized(lock){

    //執(zhí)行對共享資源的操作

    ……

}

     一些復(fù)雜的功能就很難被實現(xiàn)。比如說假如程序需要取得lock A和lock B來進(jìn)行操作1,然后需要取得lock C并且釋放lock A來進(jìn)行操作2,Java 5.0之前的多線程框架就顯得無能為力了。

   因為這些問題,程序員對舊的框架一直頗有微詞。這種情況一直到Java 5.0才有較大的改觀,一系列的多線程工具包被納入了標(biāo)準(zhǔn)庫文件。這些工具包括了一個新的多線程程序的執(zhí)行框架,使編程人員可方便地協(xié)調(diào)和調(diào)度線程的運行,并且新加入了一些高性能的常用的工具,使程序更輕易編寫,運行效率更高。本文將分類并結(jié)合例子來介紹這些新加的多線程工具。

   在我們開始介紹Java 5.0里的新Concurrent工具前讓我們先來看一下一個用舊的多線程工具編寫的程序,這個程序里有一個Server線程,它需要啟動兩個Component,Server線程需等到Component線程完畢后再繼續(xù)。相同的功能在Synchronizer一章里用新加的工具CountDownLatch有相同的實現(xiàn)。兩個程序,孰優(yōu)孰劣,哪個程序更輕易編寫,哪個程序更輕易理解,相信大家看過之后不難得出結(jié)論。

public class ServerThread {

      Object concLock = new Object();

      int count = 2;

public void runTwoThreads() {

      //啟動兩個線程去初始化組件

            new Thread(new ComponentThread1(this)).start();

            new Thread(new ComponentThread1(this)).start();

            // Wait for other thread

while(count != 0) {

                  synchronized(concLock) {

                        try {

                              concLock.wait();

                              System.out.

                        } catch (InterruptedException ie) { //處理異常}

                  }

            }

            System.out.println("Server is up.");

      }

      public void callBack() {

synchronized(concLock) {

                  count--;

                  concLock.notifyAll();

            }

      }

      public static void main(String[] args){

            ServerThread server = new ServerThread();

            server.runTwoThreads();

      }

}

 

public class ComponentThread1 implements Runnable {

      private ServerThread server;

      public ComponentThread1(ServerThread server) {

            this.server = server;

      }

public void run() {

      //做組件初始化的工作

            System.out.println("Do component initialization.");

            server.callBack();

      }

}

1:三個新加的多線程包

   Java 5.0里新加入了三個多線程包:java.util.concurrent, java.util.concurrent.atomic, java.util.concurrent.locks.

2:Callable 和 Future接口

   Callable是類似于Runnable的接口,實現(xiàn)Callable接口的類和實現(xiàn)Runnable的類都是可被其它線程執(zhí)行的任務(wù)。Callable和Runnable有幾點不同:

以下是Callable的一個例子:

public class DoCallStuff implements Callable{ // *1

        private int aInt;

        public DoCallStuff(int aInt) {

                this.aInt = aInt;

        }

        public String call() throws Exception { //*2

                boolean resultOk = false;

                if(aInt == 0){

                        resultOk = true;

                }  else if(aInt == 1){

                        while(true){ //infinite loop

                                System.out.println("looping....");

                                Thread.sleep(3000);

                        }

                } else {

                        throw new Exception("Callable terminated with Exception!"); //*3

                }

                if(resultOk){

                        return "Task done.";

                } else {

                        return "Task failed";

                }

        }

}

*1: 名為DoCallStuff類實現(xiàn)了Callable,String將是call方法的返回值類型。例子中用了String,但可以是任何Java類。

*2: call方法的返回值類型為String,這是和類的定義相對應(yīng)的。并且可以拋出異常。

*3: call方法可以拋出異常,如加重的斜體字所示。

以下是調(diào)用DoCallStuff的主程序。

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

public class Executor {

        public static void main(String[] args){

                //*1

                DoCallStuff call1 = new DoCallStuff(0);

                DoCallStuff call2 = new DoCallStuff(1);

                DoCallStuff call3 = new DoCallStuff(2);

                //*2

                ExecutorService es = Executors.newFixedThreadPool(3);

                //*3

                Future future1 = es.submit(call1);

                Future future2 = es.submit(call2);

                Future future3 = es.submit(call3);

                try {

                        //*4

                        System.out.println(future1.get());

                         //*5

                        Thread.sleep(3000);

                        System.out.println("Thread 2 terminated? :" + future2.cancel(true));

                        //*6

                        System.out.println(future3.get());

                } catch (ExecutionException ex) {

                        ex.printStackTrace();

                } catch (InterruptedException ex) {

                        ex.printStackTrace();

                }

        }

}

 


 

*1: 定義了幾個任務(wù)

*2: 初始了任務(wù)執(zhí)行工具。任務(wù)的執(zhí)行框架將會在后面解釋。

*3: 執(zhí)行任務(wù),任務(wù)啟動時返回了一個Future對象,假如想得到任務(wù)執(zhí)行的結(jié)果或者是異常可對這個Future對象進(jìn)行操作。Future所含的值必須跟Callable所含的值對映,比如說例子中Future對印Callable

*4: 任務(wù)1正常執(zhí)行完畢,future1.get()會返回線程的值

*5: 任務(wù)2在進(jìn)行一個死循環(huán),調(diào)用future2.cancel(true)來中止此線程。傳入的參數(shù)標(biāo)明是否可打斷線程,true表明可以打斷。

*6: 任務(wù)3拋出異常,調(diào)用future3.get()時會引起異常的拋出。

 運行Executor會有以下運行結(jié)果:

looping....

Task done. //*1

looping....

looping....//*2

looping....

looping....

looping....

looping....

Thread 2 terminated? :true //*3

//*4

java.util.concurrent.ExecutionException: java.lang.Exception: Callable terminated with Exception!

        at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:205)

        at java.util.concurrent.FutureTask.get(FutureTask.java:80)

        at concurrent.Executor.main(Executor.java:43)

        …….

*1: 任務(wù)1正常結(jié)束

*2: 任務(wù)2是個死循環(huán),這是它的打印結(jié)果

*3: 指示任務(wù)2被取消

*4: 在執(zhí)行future3.get()時得到任務(wù)3拋出的異常

3:新的任務(wù)執(zhí)行架構(gòu)

   在Java 5.0之前啟動一個任務(wù)是通過調(diào)用Thread類的start()方法來實現(xiàn)的,任務(wù)的提于交和執(zhí)行是同時進(jìn)行的,假如你想對任務(wù)的執(zhí)行進(jìn)行調(diào)度或是控制同時執(zhí)行的線程數(shù)量就需要額外編寫代碼來完成。5.0里提供了一個新的任務(wù)執(zhí)行架構(gòu)使你可以輕松地調(diào)度和控制任務(wù)的執(zhí)行,并且可以建立一個類似數(shù)據(jù)庫連接池的線程池來執(zhí)行任務(wù)。這個架構(gòu)主要有三個接口和其相應(yīng)的具體類組成。這三個接口是Executor, ExecutorService和ScheduledExecutorService,讓我們先用一個圖來顯示它們的關(guān)系:

 Java 5.0多線程編程(圖一)

  圖的左側(cè)是接口,圖的右側(cè)是這些接口的具體類。注重Executor是沒有直接具體實現(xiàn)的。

Executor接口:

是用來執(zhí)行Runnable任務(wù)的,它只定義一個方法:

  • execute(Runnable command):執(zhí)行Ruannable類型的任務(wù)

ExecutorService接口:

ExecutorService繼續(xù)了Executor的方法,并提供了執(zhí)行Callable任務(wù)和中止任務(wù)執(zhí)行的服務(wù),其定義的方法主要有:

  • submit(task):可用來提交Callable或Runnable任務(wù),并返回代表此任務(wù)的Future對象
  • invokeAll(collection of tasks):批處理任務(wù)集合,并返回一個代表這些任務(wù)的Future對象集合
  • shutdown():在完成已提交的任務(wù)后關(guān)閉服務(wù),不再接受新任務(wù)
  • shutdownNow():停止所有正在執(zhí)行的任務(wù)并關(guān)閉服務(wù)。
  • isTerminated():測試是否所有任務(wù)都執(zhí)行完畢了。
  • isShutdown():測試是否該ExecutorService已被關(guān)閉

ScheduledExecutorService接口

在ExecutorService的基礎(chǔ)上,ScheduledExecutorService提供了按時間安排執(zhí)行任務(wù)的功能,它提供的方法主要有:

  • schedule(task, initDelay): 安排所提交的Callable或Runnable任務(wù)在initDelay指定的時間后執(zhí)行。
  • scheduleAtFixedRate():安排所提交的Runnable任務(wù)按指定的間隔重復(fù)執(zhí)行
  • scheduleWithFixedDelay():安排所提交的Runnable任務(wù)在每次執(zhí)行完后,等待delay所指定的時間后重復(fù)執(zhí)行。

代碼:ScheduleExecutorService的例子

public class ScheduledExecutorServiceTest {

        public static void main(String[] args)

               throws InterruptedException, ExecutionException{

               //*1

                ScheduledExecutorService service = Executors.newScheduledThreadPool(2);

                //*2

                Runnable task1 = new Runnable() {

                     public void run() {

                        System.out.println("Task repeating.");

                     }

                };

                //*3

                final ScheduledFuture future1 =

                        service.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS);

                //*4

                ScheduledFuture future2 = service.schedule(new Callable(){

                     public String call(){

                             future1.cancel(true);

                             return "task cancelled!";

                     }

                }, 5, TimeUnit.SECONDS);

                System.out.println(future2.get());

//*5

service.shutdown();

        }

}

   這個例子有兩個任務(wù),第一個任務(wù)每隔一秒打印一句“Task repeating”,第二個任務(wù)在5秒鐘后取消第一個任務(wù)。

*1: 初始化一個ScheduledExecutorService對象,這個對象的線程池大小為2。

*2: 用內(nèi)函數(shù)的方式定義了一個Runnable任務(wù)。

*3: 調(diào)用所定義的ScheduledExecutorService對象來執(zhí)行任務(wù),任務(wù)每秒執(zhí)行一次。能重復(fù)執(zhí)行的任務(wù)一定是Runnable類型。注重我們可以用TimeUnit來制定時間單位,這也是Java 5.0里新的特征,5.0以前的記時單位是微秒,現(xiàn)在可精確到奈秒。

*4: 調(diào)用ScheduledExecutorService對象來執(zhí)行第二個任務(wù),第二個任務(wù)所作的就是在5秒鐘后取消第一個任務(wù)。

*5: 關(guān)閉服務(wù)。

Executors類

   雖然以上提到的接口有其實現(xiàn)的具體類,但為了方便Java 5.0建議使用Executors的工具類來得到Executor接口的具體對象,需要注重的是Executors是一個類,不是Executor的復(fù)數(shù)形式。Executors提供了以下一些static的方法:

  • callable(Runnable task): 將Runnable的任務(wù)轉(zhuǎn)化成Callable的任務(wù)
  • newSingleThreadExecutor: 產(chǎn)生一個ExecutorService對象,這個對象只有一個線程可用來執(zhí)行任務(wù),若任務(wù)多于一個,任務(wù)將按先后順序執(zhí)行。
  • newCachedThreadPool(): 產(chǎn)生一個ExecutorService對象,這個對象帶有一個線程池,線程池的大小會根據(jù)需要調(diào)整,線程執(zhí)行完任務(wù)后返回線程池,供執(zhí)行下一次任務(wù)使用。
  • newFixedThreadPool(int poolSize):產(chǎn)生一個ExecutorService對象,這個對象帶有一個大小為poolSize的線程池,若任務(wù)數(shù)量大于poolSize,任務(wù)會被放在一個queue里順序執(zhí)行。
  • newSingleThreadScheduledExecutor:產(chǎn)生一個ScheduledExecutorService對象,這個對象的線程池大小為1,若任務(wù)多于一個,任務(wù)將按先后順序執(zhí)行。
  • newScheduledThreadPool(int poolSize): 產(chǎn)生一個ScheduledExecutorService對象,這個對象的線程池大小為poolSize,若任務(wù)數(shù)量大于poolSize,任務(wù)會在一個queue里等待執(zhí)行

以下是得到和使用ExecutorService的例子:

代碼:如何調(diào)用Executors來獲得各種服務(wù)對象

//Single Threaded ExecutorService

     ExecutorService singleThreadeService = Executors.newSingleThreadExecutor();

//Cached ExecutorService

     ExecutorService cachedService = Executors.newCachedThreadPool();

//Fixed number of ExecutorService

     ExecutorService fixedService = Executors.newFixedThreadPool(3);

//Single ScheduledExecutorService

     ScheduledExecutorService singleScheduledService =

          Executors.newSingleThreadScheduledExecutor();

//Fixed number of ScheduledExecutorService

ScheduledExecutorService fixedScheduledService =

     Executors.newScheduledThreadPool(3);

4:Lockers和Condition接口

   在多線程編程里面一個重要的概念是鎖定,假如一個資源是多個線程共享的,為了保證數(shù)據(jù)的完整性,在進(jìn)行事務(wù)性操作時需要將共享資源鎖定,這樣可以保證在做事務(wù)性操作時只有一個線程能對資源進(jìn)行操作,從而保證數(shù)據(jù)的完整性。在5.0以前,鎖定的功能是由Synchronized要害字來實現(xiàn)的,這樣做存在幾個問題:

  • 每次只能對一個對象進(jìn)行鎖定。若需要鎖定多個對象,編程就比較麻煩,一不小心就會出現(xiàn)死鎖現(xiàn)象。
  • 假如線程因拿不到鎖定而進(jìn)入等待狀況,是沒有辦法將其打斷的

在Java 5.0里出現(xiàn)兩種鎖的工具可供使用,下圖是這兩個工具的接口及其實現(xiàn):

Java 5.0多線程編程(圖二)

 



發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 富蕴县| 安龙县| 镇巴县| 辽中县| 沾益县| 宁国市| 华池县| 磐石市| 临武县| 乐平市| 荥阳市| 怀集县| 平利县| 呼图壁县| 抚州市| 云梦县| 伊川县| 琼中| 玉树县| 晴隆县| 青海省| 安乡县| 和静县| 泰兴市| 金昌市| 巩留县| 精河县| 酒泉市| 手游| 遵化市| 太仆寺旗| 安福县| 北安市| 木兰县| 阿荣旗| 巨鹿县| 濮阳县| 祁阳县| 英山县| 泗阳县| 平利县|