一. 實現多線程
例
public class TestThread { int i=
上面程序的運行結果為
i=
i=
i=
結果將一直打印出I的值
通過繼承class Thread或實現Runnable接口
class Thread中有兩個最重要的函數run()和start()
例
public class TestThread extends Thread{ private static int threadCount =
運行結果為:
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