線程的創(chuàng)建
- Java語(yǔ)言的JVM允許程序運(yùn)行多個(gè)線程,它通過(guò)java.lang.Thread 類來(lái)體現(xiàn)。
- Thread類的特性 :
- 每個(gè)線程都是通過(guò)某個(gè)特定Thread對(duì)象的run()方法來(lái)完成操作的,經(jīng)常把run()方法的主體稱為線程體。
- 通過(guò)該Thread對(duì)象的start()方法來(lái)啟動(dòng)這個(gè)線程,而非直接調(diào)用run()。
方式一:繼承Thread類
- 定義子類繼承Thread類。
- 子類中重寫(xiě)Thread類中的run()方法。
- 創(chuàng)建Thread子類對(duì)象,即創(chuàng)建了線程對(duì)象。
- 調(diào)用線程對(duì)象start()方法:?jiǎn)?dòng)線程,調(diào)用run()方法。
示例代碼:
public class ThreadDemo {
public static void main(String[] args) {
MyThread mythread = new MyThread();
mythread.start();
for (int i = 0; i < 10; i++)
System.out.println("The thread 0 is running.");
}
}
class MyThread extends Thread {
public MyThread() {
super();
}
public void run() {
for (int i = 0; i < 10; i++)
System.out.println("The thread 1 is running.");
}
}
輸出:
The thread 1 is running.
The thread 1 is running.
The thread 1 is running.
The thread 1 is running.
The thread 1 is running.
The thread 1 is running.
The thread 1 is running.
The thread 1 is running.
The thread 1 is running.
The thread 0 is running.
The thread 0 is running.
The thread 0 is running.
The thread 0 is running.
The thread 0 is running.
The thread 0 is running.
The thread 0 is running.
The thread 0 is running.
The thread 0 is running.
The thread 0 is running.
The thread 1 is running.
方式二:實(shí)現(xiàn)Runnable接口
- 定義子類,實(shí)現(xiàn)Runnable接口。
- 子類中重寫(xiě)Runnable接口中的run()方法。
- 通過(guò)Thread類含參構(gòu)造器創(chuàng)建線程對(duì)象。
- 將Runnable接口的子類對(duì)象作為實(shí)際參數(shù)傳遞給Thread類的構(gòu)造器中。
- 調(diào)用Thread類的start()方法:開(kāi)啟線程,調(diào)用Runnable子類接口的run()方法。
public class ThreadDemo {
public static void main(String[] args) {
MyThread1 myThread1 = new MyThread1();
Thread t1 = new Thread(myThread1);
Thread t2= new Thread(myThread1);
t1.start();
t2.start();
for (int i = 0; i < 10; i++)
System.out.println(String.format("%s : is running.", Thread.currentThread().getName()));
}
}
public class MyThread1 extends Thread implements Runnable {
public void run() {
for (int i = 0; i < 10; i++)
System.out.println(String.format("%s : is running.", Thread.currentThread().getName()));
}
}
Thread-1 : is running.
main : is running.
Thread-1 : is running.
Thread-2 : is running.
Thread-1 : is running.
main : is running.
Thread-1 : is running.
main : is running.
Thread-2 : is running.
Thread-1 : is running.
Thread-2 : is running.
繼承方式和實(shí)現(xiàn)方式的聯(lián)系與區(qū)別:
public class Thread extends Object implements Runnable
- 區(qū)別
- 繼承Thread:線程代碼存放Thread子類run()方法中。
- 實(shí)現(xiàn)Runnable:線程代碼存在接口的子類的run()方法。
- 實(shí)現(xiàn)方式的好處
- 避免了單繼承的局限性 。
- 多個(gè)線程可以共享同一個(gè)接口實(shí)現(xiàn)類的對(duì)象,非常適合多個(gè)相同線程來(lái)處理同一份資源。
方式三: 實(shí)現(xiàn)Callable接口
與Runnable相比
- 相比run()方法,可以有返回值
- 方法可以拋出異常
- 支持泛型的返回值
- 需要借助FutureTask類,比如獲取返回結(jié)果
Future接口
- 可以對(duì)具體Runnable、Callable任務(wù)的執(zhí)行結(jié)果進(jìn)行取消、查詢是否完成、獲取結(jié)果等。
- FutrueTask是Futrue接口的唯一的實(shí)現(xiàn)類
- FutureTask 同時(shí)實(shí)現(xiàn)了Runnable, Future接口。它既可以作為Runnable被線程執(zhí)行,又可以作為Future得到Callable的返回值
方式四:使用線程池
背景:
經(jīng)常創(chuàng)建和銷毀、使用量特別大的資源,比如并發(fā)情況下的線程, 對(duì)性能影響很大.
思路:
提前創(chuàng)建好多個(gè)線程,放入線程池中,使用時(shí)直接獲取,使用完放回池中??梢员苊忸l繁創(chuàng)建銷毀、實(shí)現(xiàn)重復(fù)利用。類似生活中的公共交通工具。
優(yōu)點(diǎn):
提高響應(yīng)速度(減少了創(chuàng)建新線程的時(shí)間)
降低資源消耗(重復(fù)利用線程池中線程,不需要每次都創(chuàng)建)
便于線程管理
示例代碼:
import java.util.concurrent.*;
public class ThreadCallable {
public static void main(String[] args) {
CounterTen ct = new CounterTen();
FutureTask ft = new FutureTask(ct);
new Thread(ft).start();
try {
System.out.println(ft.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class CounterTen implements Callable {
@Override
public Object call() throws Exception {
int[] s = new int[10];
for (int i = 0; i < 10; i++) {
s[i] = i;
Thread.sleep(200);
System.out.println(Thread.currentThread().getName() + " " + i);
}
return s;
}
}
輸出:
Thread-0 0
Thread-0 1
Thread-0 2
Thread-0 3
Thread-0 4
Thread-0 5
Thread-0 6
Thread-0 7
Thread-0 8
Thread-0 9
[I@1e643faf
線程池相關(guān)API
JDK5.0起提供了線程池相關(guān)API:ExecutorService和Executors
- ExecutorService:真正的線程池接口。常見(jiàn)子類ThreadPoolExecutor
- void execute(Runnable command):執(zhí)行任務(wù)/命令,沒(méi)有返回值,一般用來(lái)執(zhí)行Runnable
- <T>Future<T> submit(Callable<T> task):執(zhí)行任務(wù),有返回值,一般又來(lái)執(zhí)行Callable
- void shutdown():關(guān)閉連接池
- Executors:工具類、線程池的工廠類,用于創(chuàng)建并返回不同類型的線程池
- Executors.newCachedThreadPool():創(chuàng)建一個(gè)可根據(jù)需要?jiǎng)?chuàng)建新線程的線程池
- Executors.newFixedThreadPool(n);創(chuàng)建一個(gè)可重用固定線程數(shù)的線程池
- Executors.newSingleThreadExecutor():創(chuàng)建一個(gè)只有一個(gè)線程的線程池
- Executors.newScheduledThreadPool(n):創(chuàng)建一個(gè)線程池,它可安排在給定延遲后運(yùn)行命令或者定期地執(zhí)行。
示例代碼:
import java.util.concurrent.*;
public class ThreadPool {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService es = Executors.newFixedThreadPool(10);
ShowOdd so = new ShowOdd();
ShowEven se = new ShowEven();
es.execute(so);
FutureTask ft = new FutureTask(se);
es.submit(ft);
Object obj =ft.get();
System.out.println(obj);
es.shutdown();
}
}
class ShowOdd implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (i % 2 == 1) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
}
}
class ShowEven implements Callable {
private int[] s = new int[5];
@Override
public Object call() throws Exception {
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
s[i/2] = i;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ": " + i);
}
}
return s;
}
}
輸出:
pool-1-thread-1: 1
pool-1-thread-2: 0
pool-1-thread-2: 2
pool-1-thread-1: 3
pool-1-thread-2: 4
pool-1-thread-1: 5
pool-1-thread-2: 6
pool-1-thread-1: 7
pool-1-thread-1: 9
pool-1-thread-2: 8
[I@2812cbfa