線程是Java的內嵌特性,線程並不容易掌握,有專門介紹Java線程的書籍,讀者可以參考。由此可見Java線程的重要性,本文將詳細介紹線程的基本知識。
有的時候你可能想寫一個程式,每隔一段時間執行相關的任務,這個時候你可以使用Timer和TimerTask,非常方便。你可以參考http://blog.csdn.net/mingjava/archive/2004/07/04/33749.aspx。
在Java中實現一個線程有兩種方法,第一是實現Runnable介面實現它的run()方法,第二種是繼承Thread類,覆蓋它的run()方法。下面是程式碼範例:
public class DoSomething implements Runnable {
public void run(){
// here is where you do something
}
}
public class DoAnotherThing extends Thread {
public void run(){
// here is where you do something
}
}
這兩種方法的區別是,如果你的類已經繼承了其它的類,那麼你只能選擇實現Runnable介面了,因為Java只允許單繼承的。
Java中的線程有四種狀態分別是:運行、就緒、掛起、結束。如果一個線程結束了也就說明他是一個死線程了。當你調用一個線程執行個體的start()的方法的時候,這個時候線程進入就緒狀態,注意並不是運行狀態,當虛擬機器開始分配給他CPU的已耗用時間片的時候線程開始進入運行狀態,當線程進入等待狀態,例如等待某個事件發生的時候,這時候線程處於掛起狀態。
啟動一個線程你只需要調用start()方法,針對兩種實現線程的方法也有兩種啟動線程的方法,分別如下:
DoSomething doIt = new DoSomething();
Thread myThread = new Thread( doIt );
myThread.start();
DoAnotherThing doIt = new DoAnotherThing();
doIt.start();
由於安全等因素Thread中的stop()方法已經不推薦使用了,因此如果你想要停止一個線程的時候可以通過設定一個訊號量,例如:
public class MyThread implements Runnable {
private boolean quit = false;
public void run(){
while( !quit ){
// do something
}
}
public void quit(){
quit = true;
}
}
如果每個線程只做它自己的事情,那麼就很簡單了,但是有的時候幾個線程可能要同時訪問一個對象並可能對它進行修改,這個時候你必須使用線程的同步在方法或者代碼塊使用關鍵字synchronized,例如:
public class Counter {
private int counter;
public synchronized int increment(){
return ++counter;
}
public synchronized int decrement(){
if( --counter < 0 ){
counter = 0;
}
return counter;
}
}
每個java對象都可以最為一個監視器,當線程訪問它的synchronized方法的時候,他只允許在一個時間只有一個線程對他訪問,讓其他得線程排隊等候。這樣就可以避免多線程對共用資料造成破壞。記住synchronized是會耗費系統資源降低程式執行效率的,因此一定要在需要同步的時候才使用,尤其在J2ME的開發中要小心。如果你要是想讓線程等待某個事件的發生然後繼續執行的話,那麼這就涉及到線程的調度了。在java中通過wait(),notify(),notifyAll()來實現,這三個方法是在Object類中定義的,當你想讓線程掛起的時候調用obj.wait()方法,在同樣的obj上調用notify()則讓線程重新開始運行。
最後以SUN提供的Producer/Consumer的例子來結束這篇文章,內容是Producer產生一個數字而Consumer消費這個數字,這個小程式裡面基本覆蓋了本文所有的知識點。請詳細研究一下代碼
public class Producer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Producer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
for (int i = 0; i < 10; i++) {
cubbyhole.put(i);
System.out.println("Producer #" + this.number
+ " put: " + i);
try {
sleep((int)(Math.random() * 100));
} catch (InterruptedException e) { }
}
}
}
public class CubbyHole {
private int contents;
private boolean available = false;
public synchronized int get() {
while (available == false) {
try {
wait();
} catch (InterruptedException e) { }
}
available = false;
notifyAll();
return contents;
}
public synchronized void put(int value) {
while (available == true) {
try {
wait();
} catch (InterruptedException e) { }
}
contents = value;
available = true;
notifyAll();
}
}
public class Consumer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Consumer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
int value = 0;
for (int i = 0; i < 10; i++) {
value = cubbyhole.get();
System.out.println("Consumer #" + this.number
+ " got: " + value);
}
}
}
public class ProducerConsumerTest { public static void main(String[] args) { CubbyHole c = new CubbyHole(); Producer p1 = new Producer(c, 1); Consumer c1 = new Consumer(c, 1); p1.start(); c1.start(); }}
SUN說輸出的結果應該是如下形式,但是在我的機器上卻不是這樣的,做了一些改動才正確,有興趣的朋友可以運行一下看看結果,歡迎和我討論一下!
Producer #1 put: 0
Consumer #1 got: 0
Producer #1 put: 1
Consumer #1 got: 1
Producer #1 put: 2
Consumer #1 got: 2
Producer #1 put: 3
Consumer #1 got: 3
Producer #1 put: 4
Consumer #1 got: 4
Producer #1 put: 5
Consumer #1 got: 5
Producer #1 put: 6
Consumer #1 got: 6
Producer #1 put: 7
Consumer #1 got: 7
Producer #1 put: 8
Consumer #1 got: 8
Producer #1 put: 9
Consumer #1 got: 9