概述:創(chuàng)建線程有兩種方法,一種是繼承Thread類,另一種是實現(xiàn)Runnable接口。
創(chuàng)建線程
創(chuàng)建線程有兩種方法:
- 繼承Thread類
- 實現(xiàn)Runnable接口
繼承Thread類
public class ExtendThead extends Thread{
private int no;
public ExtendThead(int no){
this.no = no;
}
@Override
public void run(){
try {
for(int i = 1; i <6; i++) {
System.out.println("Child Thread: " + no + "-" + i);
// 讓線程休眠一會
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}
//==============================
public class MyThread {
public static void main( String[] args ){
//注意,使用start()方法,不是run()方法。run()方法并不能啟動新的線程。
new ExtendThead(1).start();
new ExtendThead(2).start();
new ExtendThead(3).start();
new ExtendThead(4).start();
for(int i = 1; i <6; i++) {
System.out.println("Main Thread: " + i);
// 讓線程休眠一會
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
實現(xiàn)Runnable接口
public class RunnableThread implements Runnable{
private int no;
public RunnableThread(int no){
this.no = no;
}
@Override
public void run(){
try {
for(int i = 1; i <6; i++) {
System.out.println("Runnable Thread: " + no + "-" + i);
// 讓線程休眠一會
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Runnable interrupted.");
}
System.out.println("Exiting Runnable thread.");
}
}
//==============================
public class MyThread {
public static void main( String[] args ){
//注意,使用start()方法,不是run()方法。run()方法并不能啟動新的線程。
new Thread(new RunnableThread(1)).start();
new Thread(new RunnableThread(2)).start();
new Thread(new RunnableThread(3)).start();
new Thread(new RunnableThread(4)).start();
for(int i = 1; i <6; i++) {
System.out.println("Main Thread: " + i);
// 讓線程休眠一會
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
注意:實現(xiàn)Runnable接口的類沒有任何線程能力,只有將其顯示地附著在一個線程上,才會有線程能力。即只能將Runnable類的實例通過參數(shù)傳入Thread類實例來啟動線程:new Thread(Runnable).start()
。
很多情況下,使用Runnable接口創(chuàng)建線程時,直接使用匿名類的方法創(chuàng)建,會更簡單:
public static void main( String[] args ){
new Thread(new Runnable() {
@Override
public void run() {
try {
for(int i = 1; i <6; i++) {
System.out.println("Runnable Thread: " + i);
// 讓線程休眠一會
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Runnable interrupted.");
}
}
}).start();
}
Thread 和Runnable的區(qū)別
- Thread是個class,java中class只能單繼承
- Runnable是個Interface,擴展性比較好
- Runnable定義的子類中沒有start()方法,只有Thread類中才有。因此使用Runnable要通過Thread。new Thread(new Runnable)
線程的一些特征
返回值
如果希望任務完成時,返回一個結(jié)果,就不能使用Thread和Runnable。這時需要實現(xiàn)Callable接口,并必須使用ExecutorService.submit()方法來調(diào)用。
Callable定義如下。可以看到Callable接口只有一個call()
方法,并且支持返回值。
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
ExecutorService的submit方法:
public interface ExecutorService extends Executor {
<T> Future<T> submit(Callable<T> task);
}
返回值是一個Future對象。
public interface Future<V> {
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
可以通過調(diào)用Future對象的isDone()
方法來查看任務是否已經(jīng)完成。或者使用get()
方法來獲取返回結(jié)果。注意,get()
會阻塞主線程,直至子線程任務完成。所以一般情況下,在直接調(diào)用get()
方法之前,會首先使用isDone()
或者帶有超時的get()
方法查看任務是否完成。
休眠
讓線程休眠一段時間,方法是Thread.sleep(milliseconds)
線程優(yōu)先級
使用getPriority()
方法來獲取線程優(yōu)先級。
使用setPriority()
方法來設定線程的優(yōu)先級。
public class Thread implements Runnable {
**
* The minimum priority that a thread can have.
*/
public final static int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/
public final static int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/
public final static int MAX_PRIORITY = 10;
}
可以看到,JDK定義了10個優(yōu)先級。不過多數(shù)與操作系統(tǒng)映射的不好。比如Windows有7個優(yōu)先級,其映射關(guān)系還不固定。所以,為了方便移植,最好只使用Thread中定義的三種優(yōu)先級。
public class Test implements Runnable{
public void run(){
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
//do something
}
}
注意:
- 設置線程優(yōu)先級通常在
run()
方法的開頭設置。 - 極其不建議改變線程優(yōu)先級。
Daemon線程
Daemon線程即后臺線程。
與后臺線程對應的是非后臺線程。如主線程是非后臺線程,啟動的默認設置線程也是非后臺線程。
非后臺線程有個特點是:只要有任何一個非后臺線程正在運行,程序就不會終止。
與之對應,后臺線程特點是,當所有非后臺線程結(jié)束時,程序會終止,此時會結(jié)束所有后臺線程。任何一個非后臺線程結(jié)束時,都會殺死該非后臺線程啟動的后臺線程。
設置線程為后臺線程的方法:new Thread().setDaemon(true)
。
如:
Thread test = new Thread(new Runnable(){
public void run(){
//do something
}
});
test.setDaemon(true);
test.start();
可以通過isDaemon()
方法判斷一個線程是否是后臺線程。
主線程等待子線程結(jié)束
使用join
public class MyThread {
public static void main( String[] args ){
//注意,使用start()方法,不是run()方法。run()方法并不能啟動新的線程。
Thread t1 = new Thread(new RunnableThread(1)).start();
Thread t2 = new Thread(new RunnableThread(2)).start();
Thread t3 = new Thread(new RunnableThread(3)).start();
Thread t4 = new Thread(new RunnableThread(4)).start();
for(int i = 1; i <6; i++) {
System.out.println("Main Thread: " + i);
// 讓線程休眠一會
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t1.join();
t2.join();
t3.join();
t4.join();
}
}
線程池
請見 Java線程池