這種方式是最基礎的一種方式,學過java的朋友都知道,不做贅述。要注意的是:覆蓋實作使用的是run方法,運行執行緒是start方法。
public class FirstWay extends Thread { @Override public void run() { System.out.println("第一种实现线程的方式:继承Thread类"); } //模拟测试 public static void main(String[] args) { new FirstWay().start(); } }
第二種實作方式仍然很基礎,繼承Runnable接口,重寫run方法實作執行緒執行邏輯。需要注意的:執行執行緒需要套一層new Thread
。
public class SecondWay implements Runnable{ @Override public void run() { System.out.println("第二种实现线程的方式:实现Runnable接口"); } //模拟测试 public static void main(String[] args) { new Thread(new SecondWay()).start(); } }
第三種方式是實作Callable接口,Callable介面與Runable介面都能實作執行緒。
public class ThirdWay implements Callable<String> { @Override public String call() throws Exception { System.out.println("第三种实现线程的方式:实现Callable接口"); return "Callable接口带返回值,可以抛出异常"; } //模拟测试 public static void main(String[] args) throws ExecutionException, InterruptedException { FutureTask<String> futureTask = new FutureTask<>(new ThirdWay()); new Thread(futureTask).start(); //阻塞方法,获取call方法返回值 System.out.println(futureTask.get()); //打印:Callable接口带返回值,可以抛出异常 } }
差異如下:
Callable介面實作執行緒方法是call, Runable介面實作執行緒方法是run
Callable有回傳值, Runable介面不能有回傳值
Callable介面方法call回傳值可以設定泛型,如下例中使用String資料型別
Callable介面方法call方法可以拋出例外,Runable介面run方法不可以拋出例外
Callable介面方法透過new Thread(futureTask ).start()
運行,FutureTask的get方法可以取得Callable介面方法call方法的回傳值
如果Callable介面方法call方法異常,在FutureTask的get方法調用時也會拋出同樣的異常
從JDK5版本開始,java預設提供了線程池的支持,用線程池的方式運行線程可以避免線程的無限擴張導致應用宕機,同時也節省了線程頻繁創建與銷毀的資源與時間成本。
public class FourthWay implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + ":实现线程的方式Runnable接口,但运行方式不一样,使用线程池"); } public static void main(String[] args) { //创建一个固定大小的线程池 ExecutorService threadPool = Executors.newFixedThreadPool(5); for(int i = 0;i < 10;i++){ threadPool.execute(new FourthWay()); } } }
執行緒池ExecutorService使用execute方法執行Runnable介面run方法的執行緒實現,execute方法與run方法的共同特徵是沒有回傳值。
pool-1-thread-5:实现线程的方式Runnable接口,但运行方式不一样,使用线程池 pool-1-thread-2:实现线程的方式Runnable接口,但运行方式不一样,使用线程池 pool-1-thread-4:实现线程的方式Runnable接口,但运行方式不一样,使用线程池 pool-1-thread-4:实现线程的方式Runnable接口,但运行方式不一样,使用线程池 pool-1-thread-4:实现线程的方式Runnable接口,但运行方式不一样,使用线程池 pool-1-thread-1:实现线程的方式Runnable接口,但运行方式不一样,使用线程池 pool-1-thread-4:实现线程的方式Runnable接口,但运行方式不一样,使用线程池 pool-1-thread-3:实现线程的方式Runnable接口,但运行方式不一样,使用线程池 pool-1-thread-2:实现线程的方式Runnable接口,但运行方式不一样,使用线程池 pool-1-thread-5:实现线程的方式Runnable接口,但运行方式不一样,使用线程池
從上面的結果可以看出,在執行緒池中包含五個執行緒。執行緒運行完成之後並不銷毀,而是回到執行緒池,下次執行時從執行緒池中取得執行緒資源再次運行。
下面的範例執行緒池ExecutorService使用submit方法運行Callable介面call方法的執行緒實現,submit方法與call方法的共同特徵是存在返回值。
Callable介面call方法的回傳值可以由泛型定義
ExecutorService執行緒池submit方法的傳回值是Future
Future的get方法可以取得call方法的回傳值,同時如果call方法拋出例外,Future的get方法也會拋出例外。
public class FifthWay implements Callable<String> { @Override public String call() throws Exception { return Thread.currentThread().getName() + ":Callable接口带返回值,可以抛出异常"; } //模拟测试 public static void main(String[] args) throws ExecutionException, InterruptedException { //保存多线程执行结果 List<String> retList = new ArrayList<>(); //创建一个固定大小的线程池 ExecutorService threadPool = Executors.newFixedThreadPool(5); for(int i = 0;i < 10;i++){ Future<String> future = threadPool.submit(new FifthWay()); retList.add(future.get()); } //java8 语法,打印retlist retList.forEach(System.out::println); } }
上文程式碼中有一個小小的語法糖,retList.forEach(System.out::println);
是java8提供的方法參考
pool-1-thread-1:Callable接口带返回值,可以抛出异常 pool-1-thread-2:Callable接口带返回值,可以抛出异常 pool-1-thread-3:Callable接口带返回值,可以抛出异常 pool-1-thread-4:Callable接口带返回值,可以抛出异常 pool-1-thread-5:Callable接口带返回值,可以抛出异常 pool-1-thread-1:Callable接口带返回值,可以抛出异常 pool-1-thread-2:Callable接口带返回值,可以抛出异常 pool-1-thread-3:Callable接口带返回值,可以抛出异常 pool-1-thread-4:Callable接口带返回值,可以抛出异常 pool-1-thread-5:Callable接口带返回值,可以抛出异常
以上是如何在Java中創建並運行執行緒?的詳細內容。更多資訊請關注PHP中文網其他相關文章!