java創(chuàng)建線程的三種方式:
繼承Thread類創(chuàng)建線程類
通過Runable接口創(chuàng)建線程類
通過Callable和FutureTask創(chuàng)建線程
- 繼承Thread類
(1)定義Thread類的子類,并重寫該類的run方法衣迷,該run方法的方法體就代表了線程要完成的任務(wù)。因此把run()方法稱為執(zhí)行體。
(2)創(chuàng)建Thread子類的實例胶滋,即創(chuàng)建了線程對象八回。
(3)調(diào)用線程對象的start()方法來啟動該線程。
package com.nf147.Constroller;
public class FirstThreadTest extends Thread {
int i = 0;
//重寫run方法,run方法的方法體就是現(xiàn)場執(zhí)行體
public void run() {
for (; i < 100; i++) {
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
if (i == 50) {
new FirstThreadTest().start();//構(gòu)造子類對象并啟動線程
new FirstThreadTest().start();
}
}
}
}
2.創(chuàng)建Runnable方法
(1)定義runnable接口的實現(xiàn)類歌憨,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執(zhí)行體墩衙。
(2)創(chuàng)建 Runnable實現(xiàn)類的實例务嫡,并依此實例作為Thread的target來創(chuàng)建Thread對象,該Thread對象才是真正的線程對象漆改。
(3)調(diào)用線程對象的start()方法來啟動該線程心铃。
package com.nf147.Constroller;
public class RunnableThreadTest implements Runnable{ //創(chuàng)建Runnable接口類
private int i;
public void run()
{
for(i = 0;i <100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
public static void main(String[] args)
{
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
if(i==20)
{
RunnableThreadTest rtt = new RunnableThreadTest();//創(chuàng)建一個類對象
new Thread(rtt,"新線程1").start();//創(chuàng)建接口類對象并啟動
new Thread(rtt,"新線程2").start();
}
}
}
}
- 通過Callable和Future創(chuàng)建線程
(1)創(chuàng)建Callable接口的實現(xiàn)類,并實現(xiàn)call()方法挫剑,該call()方法將作為線程執(zhí)行體去扣,并且有返回值。
(2)創(chuàng)建Callable實現(xiàn)類的實例樊破,使用FutureTask類來包裝Callable對象愉棱,該FutureTask對象封裝了該Callable對象的call()方法的返回值。
(3)使用FutureTask對象作為Thread對象的target創(chuàng)建并啟動新線程哲戚。
(4)調(diào)用FutureTask對象的get()方法來獲得子線程執(zhí)行結(jié)束后的返回值
package com.nf147.Constroller;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableThreadTest implements Callable<Integer> {
public static void main(String[] args) {
CallableThreadTest ctt = new CallableThreadTest();//創(chuàng)建接口類對象
FutureTask<Integer> ft = new FutureTask<>(ctt);//由callable創(chuàng)建一個futureTask
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " 的循環(huán)變量i的值" + i);
if (i == 20) {
new Thread(ft, "有返回值的線程").start();//啟動線程
}
}
try {
System.out.println("子線程的返回值:" + ft.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception {
int i = 0;
for (; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
return i;
}
}
二奔滑、創(chuàng)建線程的三種方式的對比
采用實現(xiàn)Runnable、Callable接口的方式創(chuàng)見多線程時顺少,
- 優(yōu)勢是:
線程類只是實現(xiàn)了Runnable接口或Callable接口档押,還可以繼承其他類。
在這種方式下祈纯,多個線程可以共享同一個target對象,所以非常適合多個相同線程來處理同一份資源的情況叼耙,從而可以將CPU腕窥、代碼和數(shù)據(jù)分開,形成清晰的模型筛婉,較好地體現(xiàn)了面向?qū)ο蟮乃枷搿?/li> - 劣勢是:
編程稍微復(fù)雜簇爆,如果要訪問當前線程癞松,則必須使用Thread.currentThread()方法。
使用繼承Thread類的方式創(chuàng)建多線程時
優(yōu)勢是:
編寫簡單入蛆,如果需要訪問當前線程响蓉,則無需使用Thread.currentThread()方法,直接使用this即可獲得當前線程哨毁。劣勢是:
線程類已經(jīng)繼承了Thread類枫甲,所以不能再繼承其他父類。
package com.nf147.Constroller;
public class FirstThreadTest extends Thread {
int i = 0;
//重寫run方法扼褪,run方法的方法體就是現(xiàn)場執(zhí)行體
public void run() {
for (; i < 100; i++) {
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
if (i == 50) {
new FirstThreadTest().start();
new FirstThreadTest().start();
}
}
}
}