Java 是一種多線程編程語(yǔ)言,這意味著我們能用 java 開(kāi)發(fā)多線程程序。一個(gè)多線程程序包含兩個(gè)或更多的能并行運(yùn)行的部分,并且每一部分能最優(yōu)利用可用資源,尤其是當(dāng)你的計(jì)算機(jī)有多個(gè) CPU 時(shí),同時(shí)解決不同的任務(wù)。
多任務(wù)處理表示多個(gè)過(guò)程共同處理像CPU這樣共享的資源時(shí)。多線程將多任務(wù)處理的思想擴(kuò)展到應(yīng)用程序,你可以將一個(gè)單獨(dú)的應(yīng)用中的特定的操作細(xì)分為單獨(dú)的線程。每一個(gè)線程能并行地運(yùn)行。操作系統(tǒng)不僅在不同的應(yīng)用程序中劃分處理時(shí)間,而且在一個(gè)應(yīng)用程序中的每一個(gè)線程中也是如此。
多線程讓你可以用一種多個(gè)活動(dòng)能并行地在同一個(gè)程序中進(jìn)行的方法編寫程序。
一個(gè)線程在它的生命周期中通過(guò)不同的階段。例如,一個(gè)線程生成,開(kāi)始,運(yùn)行,然后死亡。下列的圖表展示了一個(gè)線程的完整的生命周期。
http://wiki.jikexueyuan.com/project/java/images/java_thread.jpg" alt="1" />
上述提到的階段在這解釋:
每一個(gè) Java 線程有一個(gè)幫助操作系統(tǒng)決定線程調(diào)度順序的優(yōu)先級(jí)。
Java 線程的優(yōu)先級(jí)在 MIN_PRIORITY(一個(gè)為 1 的常數(shù))和 MAX_PRIORITY(一個(gè)為 10 的常數(shù))的范圍內(nèi)。缺省狀況下,每一個(gè)線程給予優(yōu)先級(jí) NORM_PRIORITY(一個(gè)為 5 的常數(shù))。
擁有更高優(yōu)先級(jí)的線程對(duì)于一個(gè)程序來(lái)說(shuō)更加重要,應(yīng)當(dāng)在低優(yōu)先級(jí)的線程前被分配處理時(shí)間。然而,線程優(yōu)先級(jí)不能保證線程執(zhí)行和所依賴的平臺(tái)。
如果你的類想要作為一個(gè)線程被執(zhí)行,那么你可以通過(guò)實(shí)現(xiàn) Runnable 接口來(lái)到達(dá)這個(gè)目的。你將需要遵從三個(gè)基本步驟:
步驟一:
作為第一步你需要實(shí)現(xiàn)由 Runnable 接口提供的 run() 方法。這個(gè)方法為線程提供了進(jìn)入點(diǎn)并且你將把你完全的業(yè)務(wù)邏輯放入方法中。下列是簡(jiǎn)單的 run() 方法語(yǔ)法:
public void run( )
步驟二:
在第二步你將使用以下的構(gòu)造函數(shù)實(shí)例化一個(gè) Thread 對(duì)象:
Thread(Runnable threadObj, String threadName);
threadObj 是實(shí)現(xiàn) Runnable 接口的類的一個(gè)實(shí)例,threadName 是給新線程的名字。
步驟三:
一旦 Thread 對(duì)象被創(chuàng)建,你可以通過(guò)調(diào)用 run() 方法的 start() 方法來(lái)開(kāi)始它。以下是 start() 方法的簡(jiǎn)單語(yǔ)法:
void start( );
這里是一個(gè)創(chuàng)建一個(gè)新線程并使之運(yùn)行的例子:
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name){
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start ()
{
System.out.println("Starting " + threadName );
if (t == null)
{
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
這將產(chǎn)生以下結(jié)果:
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
第二個(gè)創(chuàng)建線程的方法是創(chuàng)建一個(gè)通過(guò)使用以下兩個(gè)簡(jiǎn)單步驟繼承 Thread 類的新的類。這個(gè)方法在解決 Thread 類中使用可行方法創(chuàng)建的多線程的問(wèn)題上提供了更多的靈活性。
步驟一:
你將需要覆寫 Thread 類中可用的 run()方法。這個(gè)方法為線程提供入口并且你將把你完全的業(yè)務(wù)邏輯放入方法中。以下是 run()方法的簡(jiǎn)單的語(yǔ)法。
public void run( )
步驟二:
一旦 Thread 對(duì)象被創(chuàng)建,你可以通過(guò)調(diào)用 run()方法的 start() 方法來(lái)開(kāi)始它。以下是 start() 方法的簡(jiǎn)單語(yǔ)法:
void start( );
這是前面的重寫繼承 Thread 的程序:
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name){
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// Let the thread sleep for a while.
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start ()
{
System.out.println("Starting " + threadName );
if (t == null)
{
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Thread-2");
T2.start();
}
}
這將會(huì)產(chǎn)生以下結(jié)果:
Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
以下是在 Thread 類中可以獲得的重要方法的列表。
SN | 接口描述 |
---|---|
1 | Methods with Description 在一個(gè)獨(dú)立的執(zhí)行路徑中開(kāi)始一個(gè)線程,然后在這個(gè) Thread 對(duì)象上調(diào)用 run() 方法。 |
2 | public void run() 如果這個(gè) Thread 對(duì)象是使用一個(gè)單獨(dú)的 Runnable 目標(biāo)實(shí)例化的,run()方法被 Runnable 對(duì)象調(diào)用。 |
3 | public final void setName(String name) 改變 Thread 對(duì)象的名字。也有一個(gè) getName()方法來(lái)檢索名字。 |
4 | public final void setPriority(int priority) 設(shè)置 Thread 對(duì)象的優(yōu)先級(jí)??赡艿闹翟?1 到 10 之間。 |
5 | public final void setDaemon(boolean on) 一個(gè)真值將這個(gè)線程標(biāo)志為守護(hù)進(jìn)程。 |
6 | public final void join(long millisec) 當(dāng)前進(jìn)程在第二個(gè)線程上調(diào)用這個(gè)方法,使得當(dāng)前進(jìn)程阻塞直到第二個(gè)線程終結(jié)或者指定的毫秒數(shù)過(guò)去。 |
7 | public void interrupt() 中斷這個(gè)進(jìn)程,如果由于任何原因而阻塞,使得它也繼續(xù)執(zhí)行。 |
8 | public final boolean isAlive() 如果線程是活的,返回真值,可在線程已經(jīng)開(kāi)始但在運(yùn)行到完成之前的任何時(shí)間。 |
以前的方法是被一個(gè)特殊的 Thread 對(duì)象調(diào)用的。以下在 Thread 類中的方法是靜態(tài)的。調(diào)用靜態(tài)方法會(huì)在當(dāng)前運(yùn)行的線程上執(zhí)行操作。
SN | 接口描述 |
---|---|
1 | public static void yield() 使得當(dāng)前正在運(yùn)行的線程讓步于任何其他相同優(yōu)先級(jí)的正在等待調(diào)度的線程。 |
2 | public static void sleep(long millisec) 使當(dāng)前運(yùn)行的線程阻塞至少指定的毫秒數(shù)。 |
3 | public static boolean holdsLock(Object x) 如果當(dāng)前線程持有給定對(duì)象的鎖,返回真值。 |
4 | public static Thread currentThread() 返回對(duì)當(dāng)前運(yùn)行的線程的引用,也就是調(diào)用這個(gè)方法的線程。 |
5 | public static void dumpStack() 為當(dāng)前運(yùn)行的線程打印堆棧跟蹤,這在當(dāng)調(diào)試多線程應(yīng)用程序時(shí)是有用的。 |
以下 ThreadClassDemo 程序展示了一些 Thread 類的方法??紤]實(shí)現(xiàn) Runnable 的類 DisplayMessage:
// File Name : DisplayMessage.java
// Create a thread to implement Runnable
public class DisplayMessage implements Runnable
{
private String message;
public DisplayMessage(String message)
{
this.message = message;
}
public void run()
{
while(true)
{
System.out.println(message);
}
}
}
以下是繼承 Thread 類的另一個(gè)類:
// File Name : GuessANumber.java
// Create a thread to extentd Thread
public class GuessANumber extends Thread
{
private int number;
public GuessANumber(int number)
{
this.number = number;
}
public void run()
{
int counter = 0;
int guess = 0;
do
{
guess = (int) (Math.random() * 100 + 1);
System.out.println(this.getName()
+ " guesses " + guess);
counter++;
}while(guess != number);
System.out.println("** Correct! " + this.getName()
+ " in " + counter + " guesses.**");
}
}
以下是使用上面定義的類的主程序:
// File Name : ThreadClassDemo.java
public class ThreadClassDemo
{
public static void main(String [] args)
{
Runnable hello = new DisplayMessage("Hello");
Thread thread1 = new Thread(hello);
thread1.setDaemon(true);
thread1.setName("hello");
System.out.println("Starting hello thread...");
thread1.start();
Runnable bye = new DisplayMessage("Goodbye");
Thread thread2 = new Thread(bye);
thread2.setPriority(Thread.MIN_PRIORITY);
thread2.setDaemon(true);
System.out.println("Starting goodbye thread...");
thread2.start();
System.out.println("Starting thread3...");
Thread thread3 = new GuessANumber(27);
thread3.start();
try
{
thread3.join();
}catch(InterruptedException e)
{
System.out.println("Thread interrupted.");
}
System.out.println("Starting thread4...");
Thread thread4 = new GuessANumber(75);
thread4.start();
System.out.println("main() is ending...");
}
}
這將產(chǎn)生以下結(jié)果。你可以一次一次地嘗試這個(gè)例子并且你將每次得到不同的結(jié)果。
Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......