本站不再更新,歡迎光臨 java開發技術網
          隨筆-230  評論-230  文章-8  trackbacks-0

          JAVA 多線程系統建立于 Thread 類,它的方法,它的共伴接口 Runnable 基礎上, Thread 類封裝了多線程的執行。為創建一個新的線程,你的程序必須實現 Runnabel 接口或繼承 Thread 類。

          Thread 類定義了好幾個方法來幫助管理線程,本章用到的方法表如下:

          方法

          意義

          getName

          獲得線程名

          getPrionty

          獲得線程優先級

          jsAlive

          判定線程是否仍運行

          Join

          等侍一個線程終止

          Run

          線程的入口點

          Sleep

          在一段時候時掛起線程

          Start

          通過調用運行的方法來啟動線程

          ?

          主線程

          任何一個 JAVA 都有一個主線程,當 JAVA 程序啟動時一個線程立刻運行,該線程通常叫做程序的主線程。因為它是程序開始執行時就運行,主線程的重要性體現在:

          A、 通過它產生期它子線程

          B、 通常它必須最后完成執行,因為它執行各種關閉動作。

          ?

          盡管主線程在程序啟動時自動創建,但它可以由一個 Thread 對象控制。為此,必須調用 currentThread() 獲得它的一個引用, currentThread Thread 類的公有的靜態成員:

          ?static Thread currentThread();

          該方法返回一個調用它的線程的引用。一旦獲得主線程的引用,就可以像控制其它線程那樣控制主線程。

          package com.jdk.thread;

          ?

          public class CurrentThreadDemo1 {

          ?????? /**

          ?????? ?* @param args

          ?????? ?*/

          ?????? public static void main(String[] args) {

          ????????????? Thread t=Thread.currentThread();

          ????????????? System.out.println("current thread->"+t);

          ????????????? t.setName("main thread");

          ????????????? System.out.println("change after thread name->"+t);

          ????????????? try{

          ???????????????????? for(int i=5;i>0;i--){

          ??????????????????????????? System.out.println("i-->"+i);

          ??????????????????????????? t.sleep(1000);

          ???????????????????? }

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ?????? }

          ?

          }

          以上代碼是一個最簡單的 Thread 方法例子。

          創建線程最簡單的辦法就是實現 Runnable 接口的類, Runnable 操象了一個執行代碼單元。為實現 Runnable 接口,一個類僅需實現 Run() 的簡單方法,該方法聲明如下:

          public void run();

          run 中可以定義代碼來構建新的線程, run 方法能夠像主線程那樣調用其它方法,引用其它類,聲明變量。僅有的不同是 run() 在程序中確立另一個并發程序的入口。當 run 返回時,該線程結束。這是一個例子程序:

          ?

          package com.jdk.thread;

          ?

          class newThread implements Runnable{

          ?????? Thread t;

          ??????

          ?????? public newThread(){

          ????????????? t=new Thread(this,"Demo Thread");

          ????????????? System.out.println("Client Thread ->"+t);

          ????????????? t.start();

          ?????? }

          ??????

          ?????? public void run() {

          ????????????? try{

          ???????????????????? for(int i=5;i>0;i--){

          ??????????????????????????? System.out.println("Client Thread->"+i);

          ??????????????????????????? Thread.sleep(500);

          ???????????????????? }

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ????????????? System.out.println(" 子線程結束 ");

          ?????? }

          ??????

          }

          ?

          public class CurrentThreadDemo2 {

          ?

          ?????? public static void main(String[] args) {

          ????????????? new newThread();

          ????????????? try{

          ???????????????????? for(int i=5;i>0;i--){

          ??????????????????????????? System.out.println("main Thread ->"+i);

          ??????????????????????????? Thread.sleep(1000);

          ???????????????????? }

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ????????????? System.out.println(" 主線程結束 ");

          ?????? }

          ?

          }

          通過該例子,我們應該知道 run() 方法是一個多線程的并發入口和結束方法,支持多線程的類必須要實現 Runnable 接口或繼承 Thread 類。通常主線程必須是結束運行的最后一個線程(舊版 JVM )。通常在支持多線程的類的構造函數中創建并啟動線程,創建線程就生成一個實現了 Runnable 接口的類,啟動線程就是調用該類的 start() 方法作用是運行 run() 方法。

          ?

          下面是一個創建多線程的類:

          ?

          package com.jdk.thread;

          ?

          class ThreadDemo3 implements Runnable{

          ?????? String threadName;

          ?????? Thread t;

          ?????? public ThreadDemo3(String tname){

          ????????????? this.threadName=tname;

          ????????????? t=new Thread(this,threadName);

          ????????????? t.start();

          ?????? }

          ?????? public void run() {?

          ????????????? try{

          ???????????????????? for(int i=5;i>0;i--){

          ??????????????????????????? System.out.println(threadName+"-->"+i);

          ???????????????????? }

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ????????????? System.out.println(threadName+" 結束 !");

          ?????? }

          ??????

          }

          ?

          ?

          public class Thread3 {

          ??????

          ?????? /**

          ?????? ?* @param args

          ?????? ?*/

          ?????? public static void main(String[] args) {

          ????????????? ThreadDemo3 td1=new ThreadDemo3("one");

          ????????????? ThreadDemo3 td2=new ThreadDemo3("two");

          ????????????? ThreadDemo3 td3=new ThreadDemo3("three");

          ?????????????

          ????????????? System.out.println(" 主線程結束 !");

          ?????????????

          ?????? }

          ?

          }

          輸出結果是:

          主線程結束 !

          one-->5

          one-->4

          one-->3

          one-->2

          one-->1

          one 結束 !

          two-->5

          two-->4

          two-->3

          two-->2

          two-->1

          two 結束 !

          three-->5

          three-->4

          three-->3

          three-->2

          three-->1

          three 結束 !

          當把上代碼改成這樣:

          package com.jdk.thread;

          ?

          class ThreadDemo3 implements Runnable{

          ?????? String threadName;

          ?????? Thread t;

          ?????? public ThreadDemo3(String tname){

          ????????????? this.threadName=tname;

          ????????????? t=new Thread(this,threadName);

          ????????????? t.start();

          ?????? }

          ?????? public void run() {?

          ????????????? try{

          ???????????????????? for(int i=5;i>0;i--){

          ??????????????????????????? System.out.println(threadName+"-->"+i);

          ???????????????????? }

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ????????????? System.out.println(threadName+" 結束 !");

          ?????? }

          ??????

          }

          ?

          ?

          public class Thread3 {

          ??????

          ?????? /**

          ?????? ?* @param args

          ?????? ?*/

          ?????? public static void main(String[] args) {

          ????????????? ThreadDemo3 td1=new ThreadDemo3("one");

          ????????????? ThreadDemo3 td2=new ThreadDemo3("two");

          ????????????? ThreadDemo3 td3=new ThreadDemo3("three");

          ????????????? try{

          ???????????????????? Thread t=Thread.currentThread();

          ???????????????????? t.sleep(500);

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ????????????? System.out.println(" 主線程結束 !");

          ?????????????

          ?????? }

          ?

          }

          結果如下:

          one-->5

          one-->4

          one-->3

          one-->2

          one-->1

          one 結束 !

          two-->5

          two-->4

          two-->3

          two-->2

          two-->1

          two 結束 !

          three-->5

          three-->4

          three-->3

          three-->2

          three-->1

          three 結束 !

          主線程結束 !

          ?

          使用 isAlive join

          通過前面的例子可以看出我們是使用 sleep ()方法來延時,等待子線程結束,它帶來了一個更大的問題是一個線程怎么知道另一個線程已經結束呢?通常有兩種方法可以解決:

          1、? 在線程中調用 isAlive (),這種方法由 Thread 定義,通常形式如下:

          final Boolean isAlive();

          如果調用的線程還在運行則返回 True ,否則返回 False; isAlive 很少用到,等待線程結束通常使用的方法是調用 join()

          2、? join() 形式如下:

          final void join()throw InterruptedException

          該方法等侍所調用的線程結束,該名字來自于要求線程等待直到指定的線程參與的概念。下面的例子是前面例子的改進,演示用 join() 以確保主線程最后結束??蓸右惭菔玖?/span> isAlive() 方法,代碼如下:

          package com.jdk.thread;

          ?

          class ThreadDemo3 implements Runnable{

          ?????? String threadName;

          ?????? Thread t;

          ?????? public ThreadDemo3(String tname){

          ????????????? this.threadName=tname;

          ????????????? t=new Thread(this,threadName);

          ????????????? t.start();

          ?????? }

          ?????? public void run() {?

          ????????????? try{

          ???????????????????? for(int i=5;i>0;i--){

          ??????????????????????????? System.out.println(threadName+"-->"+i);

          ???????????????????? }

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ????????????? System.out.println(threadName+" 結束 !");

          ?????? }

          ??????

          }

          ?

          ?

          public class Thread3 {

          ??????

          ?????? public static void main(String[] args) {

          ?????????????

          ????????????? ThreadDemo3 td1=new ThreadDemo3("one");

          ????????????? ThreadDemo3 td2=new ThreadDemo3("two");

          ????????????? ThreadDemo3 td3=new ThreadDemo3("three");

          ?????????????

          ????????????? System.out.println("td1 狀態 -->"+td1.t.isAlive());

          ????????????? System.out.println("td2 狀態 -->"+td2.t.isAlive());

          ????????????? System.out.println("td3 狀態 -->"+td3.t.isAlive());

          ?????????????

          ????????????? try{

          ???????????????????? System.out.println(" 等待子線程結束 !");

          ???????????????????? td1.t.join();

          ???????????????????? td2.t.join();

          ???????????????????? td3.t.join();

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ?????????????

          ????????????? System.out.println("td1 狀態 -->"+td1.t.isAlive());

          ????????????? System.out.println("td2 狀態 -->"+td2.t.isAlive());

          ????????????? System.out.println("td3 狀態 -->"+td3.t.isAlive());

          ?????????????

          ????????????? System.out.println(" 主線程結束 !");

          ?????? }

          ?

          }

          輸出的結果如下:

          td1 狀態 -->true

          td2 狀態 -->true

          td3 狀態 -->true

          等待子線程結束 !

          one-->5

          one-->4

          one-->3

          one-->2

          one-->1

          one 結束 !

          two-->5

          two-->4

          two-->3

          two-->2

          two-->1

          two 結束 !

          three-->5

          three-->4

          three-->3

          three-->2

          three-->1

          three 結束 !

          td1 狀態 -->false

          td2 狀態 -->false

          td3 狀態 -->false

          主線程結束 !

          ?

          線程的優先級別

          ?

          通常優先級別高的線程比優先級別低的線程獲得更多 CPU 時間,但實際與這與很多因素有關。就不要管這么多了,懂怎么設置線程的優選級別就 OK 。設置線程優選級別的方法如下:

          final void setPriority(int level) ; 該方法是 Thread 成員方法。 Level 的值通常是 1 10 ,也就是

          MIN_PRIORITY MAX_PRIORITY 的范圍內。

          ?

          ?

          線程同步

          當兩個或兩個以上的線程要共享一個資源是,它們需要某種方法來確定同一時刻只能有一個線程占用資源。達到此目的的過程叫做同步 (synchronization) 。

          使用同步方法,當一個線程正在同步方法內所有要訪問該同步方法的線程必須等侍,一個例子:

          package com.jdk.thread;

          ?

          class Callme{

          ??????

          ?????? public void call(String msg){

          ????????????? System.out.print("["+msg);

          ????????????? try{

          ???????????????????? Thread.sleep(1000);

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ????????????? System.out.println("]");

          ?????? }

          }

          class Caller implements Runnable{

          ?????? String msg;

          ?????? Thread t;

          ?????? Callme target;

          ??????

          ?????? public Caller(Callme targ,String s){

          ????????????? target=targ;

          ????????????? msg=s;

          ????????????? t=new Thread(this);

          ????????????? t.start();

          ?????? }

          ?????? public void run() {

          ????????????? target.call(msg);

          ?????? }

          ?

          }

          ?

          public class SynchDemo {

          ?

          ?????? public static void main(String[] args) {

          ????????????? Callme callme=new Callme();

          ????????????? Caller c1=new Caller(callme,"Hello"); // 通過多線程創建對象

          ????????????? Caller c2=new Caller(callme,"JAVA");

          ????????????? Caller c3=new Caller(callme,"C++");

          ????????????? try{

          ???????????????????? c1.t.join();

          ???????????????????? c2.t.join();

          ???????????????????? c3.t.join();

          ????????????? }catch(Exception e){

          ???????????????????? e.printStackTrace();

          ????????????? }

          ????????????? System.out.println(" 主線程結束 !");

          ?????? }

          }

          輸出的結果是:

          [Hello[JAVA[C++]

          ]

          ]

          主線程結束 ! 主線程結束 !

          ?

          在這里必須要記住多線程的同步訪問,只指對同一個對象,也就是說只有同時多個線程訪問一個對象的數據或方法時才會出現以上這種情況。因為多線程的 Caller 類,同時訪問了同一個對象 callme 的同一個方法 call() 所以就出現以上的輸了結果,顯然這不是我們想要的。

          如果我們在 Callme 類的 call ()方法前加上 synchronized 方法如下:

          ?? public synchronized void call()

          得到的結束就是 :

          [Hello]

          [JAVA]

          [C++]

          主線程結束 !

          ?

          ?

          線程間的通訊

          為了避免輪詢, JAVA 包含了通過 wait() notify() notifyAll() 實現一個進程間的通信機制。這些方法在對象中是用 final 的方法實現的。所以所有的類都含有它們,這三個方法僅在 synchronized 方法中可以調用。

          Wait() 告知被調用的線程放棄管程,進入睡眠直到其它線程進入相同的管程并調用 notify() 。

          Notify() 恢復相同對象中第一個調用 wait() 的線程。

          notifyAll() 恢復相同對象中所有調用 wait() 的線程,具有最高優先級的最先運行。

          這些方法在 Object 類中被聲明如下:

          public void wait() throws InterruptedException

          public void waitAll();

          public void notify();

          下面是一個不使用經程間通信的例程,它輸入的結果并不是我們想要的,代碼如下:

          ?

          ?

          ?

          package com.jdk.thread;

          ?

          class Q{

          ?????? int n;

          ?????? synchronized int get(){

          ????????????? System.out.println("get "+n);

          ????????????? return n;

          ?????? }

          ?????? synchronized void put(int vn){

          ????????????? this.n=vn;

          ????????????? System.out.println("put "+n);

          ?????? }

          }

          class Producer implements Runnable{

          ?????? Q q;

          ?????? public Producer(Q vq){

          ????????????? this.q=vq;

          ????????????? new Thread(this,"Producer").start();

          ?????? }

          ??????

          ?????? public void run() {

          ????????????? int i=0;

          ????????????? while(true){

          ???????????????????? q.put(i++);

          ????????????? }

          ?????? }

          ??????

          }

          class Consumer implements Runnable{

          ??????

          ?????? Q q;

          ?????? public Consumer(Q vq){

          ????????????? this.q=vq;

          ????????????? new Thread(this,"Consumer").start();

          ?????? }

          ?????? public void run() {

          ?????????????

          ????????????? while(true){

          ???????????????????? q.get();

          ????????????? }

          ?????? }

          ??????

          }

          ?

          public class SynchDemo1 {

          ?

          ?????? public static void main(String[] args) {

          ????????????? Q q=new Q();

          ????????????? new Producer(q);

          ????????????? new Consumer(q);

          ????????????? System.out.println(" 主線程結束 !");

          ?????? }

          ?

          }

          盡管在 Q 類中的 put ()和 get() 方法是同步的,沒有東西阻止生產者超越消費者。也沒有東西阻止消費者消費同樣序列多次,所以輸出結果如下:

          ?

          get 19000

          put 19001

          get 19001

          put 19002

          get 19002

          ?

          通常把 Q 類改成如下,但我還是有點不理解,為什么輸出結果不是從 1 開始呢?進程中的線程是怎么通信的呢?

          class Q{

          ?????? int n;

          ?????? boolean valueSet=false;

          ?????? synchronized int get(){

          ????????????? if(!valueSet){

          ???????????????????? try{

          ??????????????????????????? wait();

          ???????????????????? }catch(Exception e){

          ??????????????????????????? e.printStackTrace();

          ???????????????????? }

          ????????????? }

          ????????????? System.out.println("get "+n);

          ????????????? valueSet=false;

          ????????????? notify();

          ????????????? return n;

          ?????? }

          ?????? synchronized void put(int vn){

          ????????????? if(valueSet){

          ???????????????????? try{

          ??????????????????????????? wait();

          ???????????????????? }catch(Exception e){

          ??????????????????????????? e.printStackTrace();

          ???????????????????? }

          ????????????? }

          ????????????? this.n=vn;

          ????????????? valueSet=true;

          ????????????? System.out.println("put "+n);

          ????????????? notify();

          ?????? }

          }

          死鎖

          需要避免的與多任務和理有關的特殊的錯誤類型是死鎖,死鎖發生在當兩個線程對一對同步對象有循環的依懶關系時。

          ?

          ?

          線程掛起、恢復、終止

          ?

          posted on 2006-10-07 20:48 有貓相伴的日子 閱讀(445) 評論(0)  編輯  收藏 所屬分類: jdk
          本站不再更新,歡迎光臨 java開發技術網
          主站蜘蛛池模板: 牡丹江市| 固原市| 丁青县| 太原市| 永德县| 青海省| 突泉县| 米易县| 包头市| 札达县| 双鸭山市| 石城县| 绥德县| 新源县| 靖江市| 淮安市| 富裕县| 那坡县| 鄢陵县| 克东县| 伽师县| 宣武区| 称多县| 昌江| 广河县| 刚察县| 石台县| 卓尼县| 子洲县| 文成县| 凌源市| 施秉县| 珲春市| 巴马| 宝清县| 兴业县| 磴口县| 峡江县| 鄂州市| 大邑县| 蓝田县|