Java中線程的實現方式有如下三種:
1.繼承Thread類
public class Thread extends Object implements Runnable
定義Thread類的子類,並重寫Thread類的run()方法,創建子類對象(即線程對象),調用線程對象的start()方法來啓動該線程。
/**
* @Description:
* @author WEISANGENG
* @date 2017年3月3日
*/
public class ThreadDemo extends Thread {
private int i;
/**
* @功能描述: Thread線程的方式
*
* @date 2017年3月3日
* @author WEISANGENG
*/
@Override
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++) {
// currentThread是Thread類的靜態方法,該方法返回當前正在執行的線程對象
// getName()返回當前線程對象的名字
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == 20) {
// 啓動兩個線程,但是實際上有三個線程,即main主線程
// 用戶啓動的多個線程的名字依次爲Thread-0、Thread-1、、、、
new ThreadDemo().start();
new ThreadDemo().start();
}
}
}
}
/*注意:該例中第一次出現的變量i是實例變量,而每次創建線程對象時候,Thread-0和Thread-1兩個線程對象不能共享實例變量i。
即使用繼承Thread方法創建線程對象時,多個線程之間無法共享線程類的實例變量。*/
2.實現Runnable接口
public interface Runnable
定義Runnable接口的實現類,並重寫該接口的run()方法,該run()方法同樣是該線程的執行體。創建該Runnable實現類的實例,並將此實例作爲Thread的target(即構造函數中的參數)來創建Thread對象(該Thread對象纔是真正的線程對象,只是該Thread對象負責執行其target的run()方法)。最後調用線程對象的start()方法來啓動該線程。
/**
* @Description: TODO(用一句話描述該文件做什麼)
* @author WEISANGENG
* @date 2017年3月3日
*/
public class RunnableDemo implements Runnable {
private int i;
@Override
public void run() {
for (; i < 100; i++) {
// 當線程類實現Runnable接口時,只能通過Thread.currentThread()方法獲得當前線程
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) {
ThreadDemo td = new ThreadDemo();
// 創建兩個Thread對象,並且均把Runnable接口實例對象作爲target
new Thread(td).start();
new Thread(td).start();
}
}
}
}
3.使用Callable和Future
Executor是Java線程池的頂級接口
備註:ScheduledExecutorService描述的功能和Timer/TimerTask類似,解決那些需要任務重複執行的問題。這包括延遲時間一次性執行、延遲時間週期性執行以及固定延遲時間週期性執行等。當然了繼承ExecutorService的ScheduledExecutorService擁有ExecutorService的全部特性。
Executors是一個類
Executors類提供了若干個靜態方法,用於生成不同類型的線程池:
/**
* @Description: 啓動一個任務,然後等待任務的計算結果,如果等待時間超出預設定的超時時間,則中止任務。
* @author WEISANGENG
* @date 2017年3月3日
*/
public class ExecutorServiceTest {
public static void main(String[] args) {
System.out.println("Start ...");
//創建一個可緩存的線程池。如果線程池的大小超過了處理任務所需要的線程,
//那麼就會回收部分空閒(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。
//此線程池不會對線程池大小做限制,線程池大小完全依賴於操作系統(或者說JVM)能夠創建的最大線程大小。
ExecutorService exec = Executors.newCachedThreadPool();
//testTask(exec, 15); // 任務成功結束後等待計算結果,不需要等到15秒
testTask(exec, 5); // 只等待5秒,任務還沒結束,所以將任務中止
exec.shutdown();
System.out.println("End!");
}
public static void testTask(ExecutorService exec, int timeout) {
MyTask task = new MyTask();
//提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future。
//該 Future 的 get 方法在成功完成時將會返回該任務的結果。
Future<Map<String, Object>> future = exec.submit(task);
Map<String, Object> taskResult = null;
String failReason = null;
try {
// 等待計算結果,最長等待timeout秒,timeout秒後中止任務
taskResult = future.get(timeout, TimeUnit.SECONDS);
} catch (InterruptedException e) {
failReason = "主線程在等待計算結果時被中斷!";
} catch (ExecutionException e) {
failReason = "主線程等待計算結果,但計算拋出異常!";
} catch (TimeoutException e) {
failReason = "主線程等待計算結果超時,因此中斷任務線程!";
}
exec.shutdownNow();
System.out.println("\ntaskResult : " + taskResult);
System.out.println("failReason : " + failReason);
}
}
/**
*
* @Description: 任務器
* @author WEISANGENG
* @date 2017年3月3日
*/
class MyTask implements Callable<Map<String, Object>> {
@Override
public Map<String, Object> call() throws Exception {
// 總計耗時約10秒
for (int i = 0; i < 10; i++) {
Thread.sleep(1000); // 睡眠1秒
System.out.println("第"+(i+1)+"秒");
}
Map<String, Object> map = new HashMap<String, Object>();
map.put("key", "weisg81");
return map;
}
}