Java中執行緒的建立常見有如三種基本形式:
一、繼承Thread類,重寫該類別的run()方法
繼承Thread類,重寫該類別的run()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0 ;i < 50;i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
public static void main(String[] args) {
for (int i = 0;i<50;i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 10) {
new MyThread().start();
new MyThread().start();
}
}
}
}
|
登入後複製
執行結果:
1 2 3 4 5 6 7 8 9 10 | ...
main 48
main 49
Thread-0:0
Thread-0:1
Thread-0:2
Thread-0:3
Thread-0:4
Thread-1:0
...
|
登入後複製
從結果可以看出:
1、有三個執行緒:main、Thread-0 、Thread-1;
2、Thread-0 、Thread-1兩個執行緒輸出的成員變數i 的值不連續(這裡的i是實例變數而不是局部變數)。因為:透過繼承Thread類別實現多執行緒時,每個執行緒的建立都要建立不同的子類別對象,導致Thread-0 、Thread-1兩個執行緒不能共享成員變數i ;
3、執行緒的執行是搶佔式,並沒有說Thread-0 或Thread-1一直佔用CPU(這也與執行緒優先權有關,這裡Thread-0 、Thread-1執行緒優先權相同,關於執行緒優先權的知識這裡不做展開)
(學習影片推薦:java影片教學)
#二、透過實作Runnable介面建立執行緒類別
定義一個類別實作Runnable介面;建立該類別的實例對象obj;將obj當作建構器參數傳入Thread類別實例對象,這個物件才是真正的執行緒對象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0 ;i < 50 ;i++) {
System.out.println(Thread.currentThread().getName()+ ":" +i);
}
}
public static void main(String[] args) {
for (int i = 0;i < 50;i++) {
System.out.println(Thread.currentThread().getName() + ":" +i);
if (i == 10) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
new Thread(myRunnable).start();
}
}
new Thread(() -> {
System.out.println(Thread.currentThread().getName());
}, "线程3" ).start();
}
}
|
登入後複製
運行結果:
1 2 3 4 5 6 7 8 9 10 | ...
main:46
main:47
main:48
main:49
Thread-0:28
Thread-0:29
Thread-0:30
Thread-1:30
...
|
登入後複製
1、線程1和線程2輸出的成員變數i是連續的,也就是說透過這種方式創建線程,可以使多線程共享線程類的實例變量,因為這裡的多個執行緒都使用了同一個target實例變數。但是,當你使用上述的程式碼運行的時候,你會發現,其實結果有些並不連續,這是因為多個執行緒存取同一資源時,如果資源沒有加鎖,那麼會出現執行緒安全問題;
2、java8 可以使用lambda方式建立多執行緒。
三、透過Callable和Future介面建立執行緒
建立Callable介面實作類,並實作call()方法,該方法將作為執行緒執行體,且該方法有回傳值,再建立Callable實作類別的實例;使用FutureTask類別來包裝Callable對象,該FutureTask物件封裝了該Callable物件的call()方法的傳回值;使用FutureTask物件作為Thread物件的target建立並啟動新線程;呼叫FutureTask物件的get()方法來獲得子執行緒執行結束後的回傳值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public class MyCallable implements Callable<Integer> {
private int i = 0;
@Override
public Integer call() throws Exception {
int sum = 0;
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
sum += i;
}
return sum;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Integer> myCallable = new MyCallable();
FutureTask<Integer> ft = new FutureTask<Integer>(myCallable);
for (int i = 0;i<50;i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
if (i == 30) {
Thread thread = new Thread(ft);
thread.start();
}
}
System.out.println( "主线程for循环执行完毕.." );
Integer integer = ft.get();
System.out.println( "sum = " + integer);
}
}
|
登入後複製
call()方法的傳回值類型與建立FutureTask物件時<>裡的類型一致。
相關教學推薦:java快速入門
#
以上是java多執行緒的創建及啟動的詳細內容。更多資訊請關注PHP中文網其他相關文章!