熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

Java的多線程-實現多線程及線程的同步

2013-11-23 19:44:03  來源: Java高級技術 

  一. 實現多線程
  
   虛假的多線程
  例
  
  public class TestThread { int i= j=; public void go(int flag){ while(true){ try{ Threadsleep(); } catch(InterruptedException e){ Systemoutprintln(Interrupted); } if(flag==) i++; Systemoutprintln(i= + i); } else{ j++; Systemoutprintln(j= + j); } } } public static void main(String[] args){ new TestThread()go(); new TestThread()go(); }}
  
  上面程序的運行結果為
  i=
  i=
  i=
  
  結果將一直打印出I的值我們的意圖是當在while循環中調用sleep()時另一個線程就將起動打印出j的值但結果卻並不是這樣關於sleep()為什麼不會出現我們預想的結果在下面將講到
   實現多線程
  通過繼承class Thread或實現Runnable接口我們可以實現多線程
   通過繼承class Thread實現多線程
  class Thread中有兩個最重要的函數run()和start()
  ) run()函數必須進行覆寫把要在多個線程中並行處理的代碼放到這個函數中
  ) 雖然run()函數實現了多個線程的並行處理但我們不能直接調用run()函數而是通過調用start()函數來調用run()函數在調用start()的時候start()函數會首先進行與多線程相關的初始化(這也是為什麼不能直接調用run()函數的原因)然後再調用run()函數
  例
  
  public class TestThread extends Thread{ private static int threadCount = ; private int threadNum = ++threadCount; private int i = ; public void run(){ while(true){ try{ Threadsleep();  } catch(InterruptedException e){ Systemoutprintln(Interrupted); } Systemoutprintln(Thread + threadNum + = + i); if(i==) return; } } public static void main(String[] args){ for(int i=; i<5; i++) new TestThread().start(); }}
  
  運行結果為:
  Thread 1 = 5
  Thread 2 = 5
  Thread 3 = 5
  Thread 4 = 5
  Thread 5 = 5
  Thread 1 = 4
  Thread 2 = 4
  Thread 3 = 4
  Thread 4 = 4
  Thread 1 = 3
  Thread 2 = 3
  Thread 5 = 4
  Thread 3 = 3
  Thread 4 = 3
  Thread 1 = 2
  Thread 2 = 2
  Thread 5 = 3
  Thread 3 = 2
  Thread 4 = 2
  Thread 1 = 1
  Thread 2 = 1
  Thread 5 = 2
  Thread 3 = 1
  Thread 4 = 1
  Thread 5 = 1
  從結果可見,例2能實現多線程的並行處理。TW.winGWIt.COM
  **:在上面的例子中,我們只用new產生Thread對象,並沒有用reference來記錄所產生的Thread對象。根據垃圾回收機制,當一個對象沒有被reference引用時,它將被回收。但是垃圾回收機制對Thread對象“不成立”。因為每一個Thread都會進行注冊動作,所以即使我們在產生Thread對象時沒有指定一個reference指向這個對象,實際上也會在某個地方有個指向該對象的reference,所以垃圾回收器無法回收它們。
  3) 通過Thread的子類產生的線程對象是不同對象的線程
  
  class TestSynchronized extends Thread{ public TestSynchronized(String name){ super(name); } public synchronized static void prt(){ for(int i=10; i<20; i++){ System.out.println(Thread.currentThread().getName() + " : " + i); try{ Thread.sleep(100); } catch(InterruptedException e){ System.out.println("Interrupted"); } } } public synchronized void run(){ for(int i=0; i<3; i++){ System.out.println(Thread.currentThread().getName() + " : " + i); try{ Thread.sleep(100); } catch(InterruptedException e){ System.out.println("Interrupted"); } } }}public class TestThread{ public static void main(String[] args){ TestSynchronized t1 = new TestSynchronized("t1"); TestSynchronized t2 = new TestSynchronized("t2"); t1.start(); t1.start(); //(1) //t2.start(); (2) }}
  
  運行結果為:
  t1 : 0
  t1 : 1
  t1 : 2
  t1 : 0
  t1 : 1
  t1 : 2
  由於是同一個對象啟動的不同線程,所以run()函數實現了synchronized。如果去掉(2)的注釋,把代碼(1)注釋掉,結果將變為:
  t1 : 0
  t2 : 0
  t1 : 1
  t2 : 1
  t1 : 2
  t2 : 2
  由於t1和t2是兩個對象,所以它們所啟動的線程可同時訪問run()函數。
  2.2 通過實現Runnable接口實現多線程
  如果有一個類,它已繼承了某個類,又想實現多線程,那就可以通過實現Runnable接口來實現。
  1) Runnable接口只有一個run()函數。
  2) 把一個實現了Runnable接口的對象作為參數產生一個Thread對象,再調用Thread對象的start()函數就可執行並行操作。如果在產生一個Thread對象時以一個Runnable接口的實現類的對象作為參數,那麼在調用start()函數時,start()會調用Runnable接口的實現類中的run()函數。
  例3.1:
  
  public class TestThread implements Runnable{ private static int threadCount = 0; private int threadNum = ++threadCount; private int i = 5; public void run(){ while(true){ try{ Thread.sleep(100); } catch(InterruptedException e){ System.out.println("Interrupted"); } System.out.println("Thread " + threadNum + " = " + i); if(--i==0) return; } } public static void main(String[] args){ for(int i=0; i<5; i++) new Thread(new TestThread()).start(); //(1) }}
  
  運行結果為:
  Thread 1 = 5
  Thread 2 = 5
  Thread 3 = 5
  Thread 4 = 5
  Thread 5 = 5
  Thread 1 = 4
  Thread 2 = 4
  Thread 3 = 4
  Thread 4 = 4
  Thread 4 = 3
  Thread 5 = 4
  Thread 1 = 3
  Thread 2 = 3
  Thread 3 = 3
  Thread 4 = 2
  Thread 5 = 3
  Thread 1 = 2
  Thread 2 = 2
  Thread 3 = 2
  Thread 4 = 1
  Thread 5 = 2
  Thread 1 = 1
  Thread 2 = 1
  Thread 3 = 1
  Thread 5 = 1
  例3是對例2的修改,它通過實現Runnable接口來實現並行處理。代碼(1)處可見,要調用TestThread中的並行操作部分,要把一個TestThread對象作為參數來產生Thread對象,再調用Thread對象的start()函數。
  3) 同一個實現了Runnable接口的對象作為參數產生的所有Thread對象是同一對象下的線程。
  例3.2:
  
  package mypackage1;public class TestThread implements Runnable{ public synchronized void run(){ for(int i=0; i<5; i++){ System.out.println(Thread.currentThread().getName() + " : " + i); try{ Thread.sleep(100); } catch(InterruptedException e){ System.out.println("Interrupted"); } } } public static void main(String[] args){ TestThread testThread = new TestThread(); for(int i=0; i<5; i++) //new Thread(testThread, "t" + i).start(); (1) new Thread(new TestThread(), "t" + i).start(); (2) }}
  
  運行結果為:
  t0 : 0
  t1 : 0
  t2 : 0
  t3 : 0
  t4 : 0
  t0 : 1
  t1 : 1
  t2 : 1
  t3 : 1
  t4 : 1
  t0 : 2
  t1 : 2
  t2 : 2
  t3 : 2
  t4 : 2
  t0 : 3
  t1 : 3
  t2 : 3
  t3 : 3
  t4 : 3
  t0 : 4
  t1 : 4
  t2 : 4
  t3 : 4
  t4 : 4
  由於代碼(2)每次都是用一個新的TestThread對象來產生Thread對象的,所以產生出來的Thread對象是不同對象的線程,所以所有Thread對象都可同時訪問run()函數。如果注釋掉代碼(2),並去掉代碼(1)的注釋,結果為:
  t0 : 0
  t0 : 1
  t0 : 2
  t0 : 3
  t0 : 4
  t1 : 0
  t1 : 1
  t1 : 2
  t1 : 3
  t1 : 4
  t2 : 0
  t2 : 1
  t2 : 2
  t2 : 3
  t2 : 4
  t3 : 0
  t3 : 1
  t3 : 2
  t3 : 3
  t3 : 4
  t4 : 0
  t4 : 1
  t4 : 2
  t4 : 3
  t4 : 4
  由於代碼(1)中每次都是用同一個TestThread對象來產生Thread對象的,所以產生出來的Thread對象是同一個對象的線程,所以實現run()函數的同步。
  
  二. 共享資源的同步
  
  1. 同步的必要性
  例4:
  
  class Seq{ private static int number = 0; private static Seq seq = new Seq(); private Seq() {} public static Seq getInstance(){ return seq; } public int get(){ number++;  //(a) return number; //(b) }}public class TestThread{ public static void main(String[] args){ Seq.getInstance().get(); //(1) Seq.getInstance().get(); //(2) }}
  
  上面是一個取得序列號的單例模式的例子,但調用get()時,可能會產生兩個相同的序列號:
  當代碼(1)和(2)都試圖調用get()取得一個唯一的序列。當代碼(1)執行完代碼(a),正要執行代碼(b)時,它被中斷了並開始執行代碼(2)。一旦當代碼(2)執行完(a)而代碼(1)還未執行代碼(b),那麼代碼(1)和代碼(2)就將得到相同的值。
  2. 通過synchronized實現
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27373.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.