Vincent.Chan‘s Blog

          常用鏈接

          統(tǒng)計

          積分與排名

          網(wǎng)站

          最新評論

          多線程(3):JT第2章筆記

          Chapter2: Thread Creation and Management

          2.1 What Is a Thread?

          介紹了什么是線程,以及線程(thread, multithread)與進程(process, mutltitask)的區(qū)別。其中的一個重要區(qū)別是對共享數(shù)據(jù)的訪問。進程可以共享操作系統(tǒng)級別的某些數(shù)據(jù)區(qū)域,如剪貼板;而線程是對程序自有的數(shù)據(jù)進 行共享。進程之間對共享數(shù)據(jù)的存取方法是特殊的,因此自然能夠得到程序員的注意;而線程之間對共享數(shù)據(jù)的存取與對線程自己的數(shù)據(jù)的存取方法是一樣的,所以 常常比較隱蔽,而被程序員忽略。其實,這也是多線程開發(fā)比較難的地方。所以,這一節(jié)最后說:"A thread, then, is a discrete task that operates on data shared with other threads.(線程就是一個在與其它線程共享的數(shù)據(jù)上進行操作的單獨任務(wù)。)"

          2.2 Creating a Thread

          1. 有兩種方法創(chuàng)建線程:使用Thread類或者Runnable接口
          2. 示例程序竟然是編一個打字游戲,所以,這本書的門檻還是有點高的:(。當然可以從該書的站點直接下載代碼。

          3. Thread class
          package java.lang;
          public class Thread implements Runnable {
          public Thread( );
          public Thread(Runnable target);
          public Thread(ThreadGroup group, Runnable target);
          public Thread(String name);
          public Thread(ThreadGroup group, String name);
          public Thread(Runnable target, String name);
          public Thread(ThreadGroup group, Runnable target, String name);
          public Thread(ThreadGroup group, Runnable target, String name,
          long stackSize);
          public void start( );
          public void run( );
          }
          Thread name: 線程名,用以打印線程信息時用,缺省為Thread-N。
          Runnable target:可運行的目標。一個可運行的對象就是一串可由線程執(zhí)行的指令。缺省就是在run()方法中編寫的內(nèi)容。
          Thread group:線程組。對于大多數(shù)應(yīng)用來說沒什么意義,缺省在同一組。
          Stack size:線程堆棧大小,與平臺相關(guān)。為了使程序更具可移植性,并不推薦使用。

          2.3 The Lifecycle of a Thread

           

          1. Creating a Thread:創(chuàng)建一個線程對象,并沒有開始執(zhí)行一個線程
          2. Starting a Thread:在調(diào)用線程對象的start()方法前,一直處于等待狀態(tài)??梢酝ㄟ^調(diào)用isAlive()方法來獲取線程是否正在運行;
          3. Terminating a Thread:線程在以下情況下結(jié)束  
            1)執(zhí)行完run()中的語句;
            2)拋出一個異常,包括其沒有捕獲的異常;
            3)其所在的程序(或者容器)調(diào)用System.exit()。
          注意:一個線程結(jié)束后,就不能再次啟動,該線程就變成一個普通的對象,如果試圖再次調(diào)用start()方法,將拋出java.lang.IllegalThreadStateException異常。如果想多次運行,要么創(chuàng)建新的對象;要么就是不要結(jié)束該線程。
          4. Java并沒有提供可靠的方法來暫停、掛起或者重啟一個線程的方法,線程本身能通過sleep()函數(shù)來暫停執(zhí)行。目前依然只能確保若干毫秒級別的精度。
          5. Thread Cleanup:線程終止后,線程對象依然存在。可以通過join()方法以阻塞方式(blocked)來等待某個線程終止。

          2.4 Two Approches to Stop a Thread

          1. Setting a Flag:在線程的執(zhí)行過程中判斷其它線程是否將標志置位。其缺點是有時間延遲,尤其是當進入了某些被阻塞的函數(shù)如:sleep(), wait()等;
          2. 調(diào)用線程的interrupt()方法, 線程的執(zhí)行過程中改為判斷isInterrupted()的返回值??梢越鉀Q線程進入阻塞導(dǎo)致的延遲,但依然解決不了超長時間計算而導(dǎo)致的延遲。 interrupt()有兩個作用:1)終止sleep()和wait(),拋出InterruptedException;2)使 isInterrupted()返回true。下面這段代碼將演示interrupt()的作用:

          public class TestInterrupted {
          public static void main(String args[]) throws InterruptedException{
          Foo foo = new Foo();
          foo.start();
          Thread.currentThread().sleep(100); //注釋掉這句有什么影響呢?
          System.out.println("before interrupt");
          foo.interrupt();
          System.out.println("after interrupt");
          } }

          class Foo extends Thread {
          public void run() {
          try{
          while(!isInterrupted()) {
          System.out.println("start calculating...");
          double pi = 3.1415926;
          for(int i=0; i<5; i++) {
          for(long j=0; j<1000000; j++) {
          pi *= pi;
          }
          System.out.println("i="+i);
          }
          System.out.println("before sleep");
          sleep(5000); //注釋掉這句及相關(guān)的try...catch語句,又怎樣呢?
          System.out.println("after sleep");
          }
          } catch(InterruptedException ex) {
          ex.printStackTrace(System.out);
          }
          }
          }

           

          2.5 The Runnable Interface

          為什么有了Thread類,還要有Runnable接口呢?最主要的原因是為了解決Java不能多重繼承的問題。線程繼承自 Thread,還是僅僅實現(xiàn)Runnable接口,取決于這個線程的作用。不過,如果僅僅實現(xiàn)Runnable接口,則在線程里不能使用Thread類的 方法,比如interrupt()和isInterrupted()。當然,這個還是要取決于實際情況。

          2.6 Threads and Objects

          主要講解線程與對象的關(guān)系。線程根本上還是個對象,其可以存取任何對象包括其它線程對象,當然也能被其它對象存取,只要沒有因 為爭奪公共資源而被鎖定,線程對象中的任何屬性和方法都有可能同時執(zhí)行。并且Java中的鎖只針對對象本身,并不包括對象下的屬性;而對方法同步,則等同 于對對象同步。更進一步的說明還可以參考《Practical Java》中的"實踐46:面對instance函數(shù),synchronized鎖定的是對象(object)而非函數(shù)(methods)或代碼 (code)"。下面用兩段代碼來說明一下:
          代碼1:

          public class TestLock {
          public static void main(String args[])
          throws InterruptedException{
          Foo foo = new Foo();
          foo.start();
          Thread t = Thread.currentThread();
          for(int i=0; i<10; i++) {
          foo.setInt2("Main", i, i+20);
          }
          }
          }

          class Foo extends Thread{
          protected int arrI[] = new int[10];

          public void run() {
          try {
          for(int i=0; i<10; i++) {
          setInt("Foo", i, i);
          }
          } catch(InterruptedException ex) {}
          }

          public synchronized void setInt(String from, int pos, int val)
          throws InterruptedException{
          arrI[pos] = val;
          sleep((long)(Math.random()*5000));
          System.out.println(from+":arrI["+pos+"]="+arrI[pos]);
          }

          public void setInt2(String from, int pos, int val)
          throws InterruptedException {
          synchronized(arrI){
          arrI[pos] = val;
          sleep((long)(Math.random()*5000));
          System.out.println(from+":arrI["+pos+"]="+arrI[pos]);
          }
          }
          }
          結(jié)果:非線程安全,setInt()在對象上加鎖,而setInt2()在屬性arrI上加鎖,不同的鎖不能保證線程安全。可能的結(jié)果如下:
          Foo:arrI[0]=0 
          Main:arrI[0]=0
          Main:arrI[1]=21
          Main:arrI[2]=22
          Foo:arrI[1]=21
          Main:arrI[3]=23
          Main:arrI[4]=24
          Main:arrI[5]=25
          Foo:arrI[2]=2
          Main:arrI[6]=26
          Main:arrI[7]=27
          Foo:arrI[3]=3
          Foo:arrI[4]=4
          Main:arrI[8]=28
          Main:arrI[9]=29
          Foo:arrI[5]=5
          Foo:arrI[6]=6
          Foo:arrI[7]=7
          Foo:arrI[8]=8
          Foo:arrI[9]=9

          代碼2:
          public class TestLock1 {
          public static void main(String args[])
          throws InterruptedException{
          Foo1 foo = new Foo1();
          foo.start();
          Thread t = Thread.currentThread();
          for(int i=0; i<10; i++) {
          foo.setInt2("Main", i, i+20);
          }
          }
          }

          class Foo1 extends Thread{
          protected int arrI[] = new int[10];

          public void run() {
          try{
          for(int i=0; i<10; i++) {
          setInt("Foo", i, i);
          }
          }catch(InterruptedException ex){}
          }

          public synchronized void setInt(String from, int pos, int val)
          throws InterruptedException{
          arrI[pos] = val;
          sleep((long)(Math.random()*5000));
          System.out.println(from+":arrI["+pos+"]="+arrI[pos]);
          }

          public synchronized void setInt2(String from, int pos, int val)
          throws InterruptedException{
          arrI[pos] = val;
          sleep((long)(Math.random()*5000));
          System.out.println(from+":arrI["+pos+"]="+arrI[pos]);
            }
          }
          結(jié)果:線程安全

          posted on 2006-03-09 22:58 Vincent.Chen 閱讀(113) 評論(0)  編輯  收藏 所屬分類: Java

          主站蜘蛛池模板: 仙桃市| 靖远县| 荆门市| 张家界市| 毕节市| 韩城市| 新蔡县| 偏关县| 轮台县| 江山市| 金塔县| 萍乡市| 驻马店市| 紫阳县| 尚义县| 东安县| 唐河县| 祁阳县| 阳西县| 长葛市| 瓦房店市| 新化县| 乌兰浩特市| 德兴市| 舒城县| 临漳县| 吕梁市| 马龙县| 威远县| 灌云县| 苏尼特右旗| 达日县| 集安市| 瑞安市| 辽源市| 龙口市| 武胜县| 拜城县| 南安市| 雷州市| 中宁县|