日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

 

前言

并發是一件很美妙的事情,線程的調度與使用會讓你除了業務代碼外,有新的世界觀,無論你是否參與但是這對于你未來的成長幫助很大。

所以,讓我們來好好看看在JAVA中啟動線程的那幾個方式與介紹。

Thread

對于 Thread 我想這個基本上大家都認識的,在Java源碼是這樣說: java 虛擬機允許應用程序同時運行多個執行線程。 而這個的 Thread 就是程序的執行線程。

如何使用它呢,其實在這個類中的源碼已經給我們寫好了,甚至是下面的 Runnable 的使用方式。(如下是Thread源碼)

/** * A <i>thread</i> is a thread of execution in a program. The Java * Virtual machine allows an Application to have multiple threads of * execution running concurrently. * <hr><blockquote><pre> * class PrimeThread extends Thread { * long minPrime; * PrimeThread(long minPrime) { * this.minPrime = minPrime; * } * * public void run() { * // compute primes larger than minPrime * . . . * } * } * </pre></blockquote><hr> * <p> * The following code would then create a thread and start it running: * <blockquote><pre> * PrimeThread p = new PrimeThread(143); * p.start(); * </pre></blockquote> * <p> * <hr><blockquote><pre> * class PrimeRun implements Runnable { * long minPrime; * PrimeRun(long minPrime) { * this.minPrime = minPrime; * } * * public void run() { * // compute primes larger than minPrime * . . . * } * } * </pre></blockquote><hr> * <p> * The following code would then create a thread and start it running: * <blockquote><pre> * PrimeRun p = new PrimeRun(143); * new Thread(p).start(); * </pre></blockquote> * <p> */public class Thread implements Runnable {
 //...}

閱讀源碼的信息其實是最全的 ,我截取了部分的注釋信息,起碼我們現在可以無壓力的使用這個兩個方式來啟動自己的線程。

如果我們還要傳遞參數的話,那么我們設定一個自己的構造函數也是可以,如下方式:

public class MyThread extends Thread {
 public MyThread(String name) {
 super(name);
 }
 @Override
 public void run() {
 System.out.println("一個子線程 BY " + getName());
 }}

這時讀者應該發現,這個構造函數中的 name ,居然在 Thread 中也是有的,其實在Java中的線程都會自己的名稱,如果我們不給其定義名稱的話,java也會自己給其命名。

/** * Allocates a new {@code Thread} object. This constructor has the same * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread} * {@code (null, null, name)}. * * @param name * the name of the new thread */public Thread(String name) {
 init(null, null, name, 0);}

而我們最核心,也是大家最在意的應該就是如何啟動并執行我們的線程了,是的,這個大家都知道的,就是這個 run 方法了。

同時大家如果了解過了 Runnable ,我想大家都會知道這個 run 方法,其實是 Runnable 的方法,而我們本節的 Thread 也是實現了這個接口。

這里,大家可能會好奇,不是應該是 start 這個方法嗎?那么讓我們看看 start 的源碼。

/** * Causes this thread to begin execution; the Java Virtual Machin * calls the <code>run</code> method of this thread. */public synchronized void start() {
 //...}

通過 start 方法,我們可以了解到,就如同源碼的啟動模板中那樣,官網希望,對于線程的啟動,使用者是通過 start 的方式來啟動線程,因為這個方法會讓Java虛擬機會調用這個線程的 run 方法。

其結果就是,一個線程去運行 start 方法,而另一個線程則取運行 run 方法。同時對于這樣線程,Java官方也說了,線程是不允許多次啟動的,這是不合法的。

所以如果我們執行下面的代碼,就會報 java.lang.IllegalThreadStateException 異常。

MyThread myThread = new MyThread("Thread");myThread.start();myThread.start();

但是,如果是這樣的代碼呢?

MyThread myThread = new MyThread("Thread");myThread.run();myThread.run();myThread.start();//運行結果一個子線程 BY Thread一個子線程 BY Thread一個子線程 BY Thread

這是不合理的,如果大家有興趣,可以去試試并動手測試下,最好開調試模式。

下面我們再看看,連 Thread 都要實現,且核心的 run 方法出處的 Runnable 。

Runnable

比起 Thread 我希望大家跟多的使用 Runnable 這個接口實現的方式,對于好壞對比會在總結篇說下。

我想大家看 Runnable 的源碼會更加容易與容易接受,畢竟它有一個 run 方法。(如下為其源碼)

/** * The <code>Runnable</code> interface should be implemented by any * class whose instances are intended to be executed by a thread. The * class must define a method of no arguments called <code>run</code>. */@FunctionalInterfacepublic interface Runnable {
 /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. */
 public abstract void run();}

首先,所有打算執行線程的類均可實現這個 Runnable 接口,且必須實現 run 方法。

它將為各個類提供一個協議,就像 Thread 一樣,其實當我們的類實現了 Runnable 的接口后,我們的類與 Thread 是同級,只是可能僅有 run 方法,而沒有 Thread 提供的跟豐富的功能方法。

而對于 run 方法,則是所有實現了 Runnable 接口的類,在調用 start 后,將使其單獨執行 run 方法。

那么我們可以寫出這樣的測試代碼。

MyThreadRunnable myThreadRunnable = new MyThreadRunnable("Runnabel");myThreadRunnable.run();new Thread(myThreadRunnable).start();Thread thread = new Thread(myThreadRunnable);thread.start();thread.start();//運行效果Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.start(Thread.java:705)
	at com.github.myself.runner.RunnableApplication.main(RunnableApplication.java:14)這是一個子線程 BY Runnabel這是一個子線程 BY Runnabel這是一個子線程 BY Runnabel

同樣的,線程是不允許多次啟動的,這是不合法的。

同時,這時我們也看出了使用 Thread 與 Runnable 的區別,當我們要多次啟用一個相同的功能時。

我想 Runnable 更適合你。

但是,用了這兩個方式,我們要如何知道線程的運行結果呢???

FutureTask

這個可能很少人(初學者)用到,不過這個現在是我最感興趣的。它很有趣。

其實還有一個小兄弟,那就是 Callable。 它們是一對搭檔。如果上面的內容,你已經細細品味過,那么你應該已經發現 Callable 了。

沒錯,他就在 Runnable 的源碼中出現過。

/** * @author Arthur van Hoff * @see java.lang.Thread * @see java.util.concurrent.Callable * @since JDK1.0 */
 @FunctionalInterfacepublic interface Runnable {}

那么我們先去看看這個 Callable 吧。(如下為其源碼)

/** * A task that returns a result and may throw an exception. * Implementors define a single method with no arguments called * {@code call}. */@FunctionalInterfacepublic interface Callable<V> {
 /** * Computes a result, or throws an exception if unable to do so. * * @return computed result * @throws Exception if unable to compute a result */
 V call() throws Exception;}

其實,這是一個與 Runnable 基本相同的接口,當時它可以返回執行結果與檢查異常,其計算結果將由 call() 方法返回。

那么其實我們現在可以寫出一個實現的類。

public class MyCallable implements Callable {
 private String name;
 public MyCallable(String name) {
 this.name = name;
 }
 @Override
 public Object call() throws Exception {
 System.out.println("這是一個子線程 BY " + name);
 return "successs";
 }}

關于更深入的探討,我將留到下一篇文章中。

好了,我想我們應該來看看 FutureTask 這個類的相關信息了。

/** * A cancellable asynchronous computation. This class provides a base * implementation of {@link Future}, with methods to start and cancel * a computation, query to see if the computation is complete, and * retrieve the result of the computation. The result can only be * retrieved when the computation has completed; the {@code get} * methods will block if the computation has not yet completed. Once * the computation has completed, the computation cannot be restarted * or cancelled (unless the computation is invoked using * {@link #runAndReset}). */
 public class FutureTask<V> implements RunnableFuture<V> {
 //...
 }

源碼寫的很清楚,這是一個可以取消的異步計算,提供了查詢、計算、查看結果等的方法,同時我們還可以使用 runAndRest 來讓我們可以重新啟動計算。

在查看其構造函數的時候,很高興,我們看到了我們的 Callable 接口。

/** * Creates a {@code FutureTask} that will, upon running, execute the * given {@code Callable}. * * @param callable the callable task * @throws NullPointerException if the callable is null */public FutureTask(Callable<V> callable) {
 if (callable == null)
 throw new NullPointerException();
 this.callable = callable;
 this.state = NEW; // ensure visibility of callable}

即我們將創建一個未來任務,來執行 Callable 的實現類。那么我們現在可以寫出這樣的代碼了。

final FutureTask fun = new FutureTask(new MyCallable("Future"));

那么接下來我們就可以運行我們的任務了嗎?

是的,我知道了 run() 方法,但是卻沒有 start 方法。

官方既然說有結果,那么我找到了 get 方法。同時我嘗試著寫了一下測試代碼。

public static void main(String[] args) {
 MyCallable myCallable = new MyCallable("Callable");
 final FutureTask fun = new FutureTask(myCallable);
 fun.run();
 try {
 Object result = fun.get();
 System.out.println(result);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } catch (ExecutionException e) {
 e.printStackTrace();
 }}

運行效果,是正常的,這好像是那么回事。

//運行效果這是一個子線程 BY Callablesuccesss

可是,在我嘗試著加多一些代碼的時候,卻發現了一些奇妙的東西 。

我加多了一行 fun.run(); 代碼,同時在 MyCallable 類中,將方法加一個時間線程去等待3s。

結果是: 結果只輸出了一次,同時 get 方法需要等運行3s后才有返回。

這并不是我希望看到的。但是,起碼我們可以知道,這次即使我們多次運行使用 run 方法,但是這個線程也只運行了一次。這是一個好消息。

同時,我們也拿到了任務的結果,當時我們的進程被阻塞了,我們需要去等我們的任務執行完成。

最后,在一番小研究后,以下的代碼終于完成了我們預期的期望。

public static void main(String[] args) {
 MyCallable myCallable = new MyCallable("Callable");
 ExecutorService executorService = Executors.newCachedThreadPool();
 final FutureTask fun = new FutureTask(myCallable);
 executorService.execute(fun);// fun.run(); //阻塞進程
 System.out.println("--繼續執行");
 try {
 Object result = fun.get();
 System.out.println(result);
 } catch (InterruptedException e) {
 e.printStackTrace();
 } catch (ExecutionException e) {
 e.printStackTrace();
 }}

我們使用線程池去運行我們的 FutureTask 同時使用 get 方法去獲取運行后的結果。結果是友好的,進程并不會被阻塞。

關于更深入的探討,我將留到下一篇文章中。

總結一波

好了,現在應該來整理以下了。

  • Thread 需要我們繼承實現,這是比較局限的,因為Java的 繼承資源 是有限的,同時如果多次執行任務,還需要 多次創建任務類
  • Runnable 以接口的形式讓我們實現,較為方便,同時多次執行任務也無需創建多個任務類,當時僅有一個 run 方法。
  • 以上兩個方法都 無法獲取任務執行結果 ,FutureTask可以獲取任務結果。同時還有更多的新特性方便我們使用···

分享到:
標簽:線程 Java
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定