GitHubのプログラム猿協会は、歓迎スター
https://github.com/ITfqyd/cxyxsを
対応するトピックを形成するために、この記事では、githubのに記録されています。
記事のディレクトリ
序文
最後の章によって、我々は達成することを学んだ、マルチスレッド、マルチスレッドの方法を達成するためのいくつかの方法があります。しかし、一般的に我々はそれが二種類ある知っ継承Threadクラスと実行可能なインタフェースを実装します。マルチスレッドのための呼び出し可能インターフェース非常に奇妙な、我々はそれが呼び出し可能であるかを理解するために、学ぶためにソースコードに目を通します。
1.Callable過去と現在
、Runnableインタフェースまたはを通じて、マルチスレッド達成するための継承スレッドは、我々はあなたが共有変数の方法により取得することができ、スレッドの実行結果を取得したいです。この問題を解決するために、中ジャワJDK1.5は呼び出し可能な、未来のインターフェイスで導入します。
1.1呼び出し可能な過去のRunnable
package com.cxyxs.thread.three;
import java.util.Date;
/**
* Description:转发请注明来源 程序猿学社 - https://ithub.blog.csdn.net/
* Author: 程序猿学社
* Date: 2020/2/17 21:43
* Modified By:
*/
public class MyThreadRunnable implements Runnable{
//测试账号
private int count=0;
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyThreadRunnable run = new MyThreadRunnable();
Thread thread = new Thread(run);
thread.start();
try {
//等待线程执行完毕,不然获取不到最终的结果
thread.join();
System.out.println(run.count);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
テスト結果
- このように、我々は達成されていない、結果はスレッドを取得します。今、私たちが実行可能を通じて道をまとめ、それがマルチスレッドインタフェースのリターンを得る方法です。
- 実装、Runnableインタフェースはrunメソッド、および私たちが必要とする結果を受け取るためにメンバ変数を定義するクラスを定義します。
- 呼び出されると、クラスはパラメータがスレッドを通過したとして、startメソッドは、スレッドの開始と呼ばれるインスタンス化されます
- この方法は、我々は5つのスレッドの実装後の結果を得る、または0であることができるように、終了したスレッドを待って、スレッドを呼び出して参加します。
人生の1.2呼び出し可能
FutureTask +スレッドを呼び出すことにより、
package com.cxyxs.thread.three;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
/**
* Description:转发请注明来源 程序猿学社 - https://ithub.blog.csdn.net/
* Author: 程序猿学社
* Date: 2020/2/19 0:12
* Modified By:
*/
public class MyThreadCallable {
public static void main(String[] args) throws Exception{
//第一步
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int count=0;
for (int i = 0; i < 5; i++) {
Thread.sleep(1200);
count++;
}
return count;
}
};
FutureTask<Integer> task = new FutureTask<>(callable);
Thread thread = new Thread(task);
thread.start();
Integer result = task.get();
System.out.println("获取多线程的值:"+result);
}
}
- 怠け者であるために、ここでは最初のステップを省略し、呼び出し可能インターフェースは、私はここに速記法を使用して、コールを書き換え、一般的にクラスが実装されています。
- FutureTaskの例としては、形状パラメータは、コンストラクタに渡され、呼び出し可能なクラスを達成します。
- スレッド、形状の構成パラメータを渡す方法としてオブジェクトFutureTaskの例。
- getメソッドのFutureTaskオブジェクトを呼び出します。あなたは値を取得することができます。
ExecutorServiceの+フューチャーコールの実装
public void two() throws Exception{
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int count=0;
for (int i = 0; i < 5; i++) {
Thread.sleep(1200);
count++;
}
return count;
}
};
ExecutorService e= Executors.newFixedThreadPool(10);
Future<Integer> f1=e.submit(callable);
Integer result = f1.get();
System.out.println("获取多线程的值:"+result);
}
この方法で、複数のスレッドによって管理されるスレッドプールを使用することをお勧めします。
質問を頼む、なぜスレッドプールを使用できますか?
スレッドを作成し、破壊の数を減らすために、各スレッドは、複数回使用することができます。
ここでは、理解することができます。私はそのようなことを知っています。プレゼンテーションのスレッドプール関連のフォローアップ関連の記事があります。
2.ソース解析
彼は我々だけで呼び出し可能なスレッドを実装する方法を多段階でまとめてきたのと同様に、あまり話をしませんでした。私たちは道+フューチャーExecutorServiceのコールの実装を分析する、のは彼のソースを見てもらうことステップバイステップを始めましょう。友愛の余暇を持って、あなたは自分のソースFutureTaskを参照してください+この方法のコールをスレッドに試すことができます。
2.1呼び出し可能インタフェースを達成するための最初のステップは
呼び出し可能インターフェース
@FunctionalInterface
public 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インタフェース
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
ソースコードを読んだ後、あなたのロータリアンはそれインターフェース呼び出し可能とのRunnableの違いについて話すことができますか?
- 別のメソッド名、呼び出し可能なコールは、Runnableをが実行されています
- 呼び出し可能な方法は、Runnableを抽象メソッドです
- 呼び出し可能な例外がスローされ、Runnableをは例外をスローしません
- 呼び出し可能な戻り値V、Runnableをノーリターン値。
- 私たちは、get経由で呼び出されたときに呼び出し可能にジェネリックを定義することができ、あなたは箱を開梱する必要はありません。
例外を返すに非常に重要な呼び出し可能な利点となる値を、投げている間、それは痛みのポイントのRunnableを、いくつかの問題を解決するために、です。
図2.2 FutureTaskクラス構造。
まず、クラス構造のfutureTaskで見てみましょう。選択digrams->ショー(digrams右アイデアは、アイデアのバージョン)
このマップによって、我々は良いに対応関係を参照することができ、Cクラスを示し、Iはインタフェースである
関数インタフェース@FunctionalInterface。
この図、一つずつ、ソース・分析は、私たちによります。
チャートでは、私たちは私たちが詳しく見てみましょう、FutureTaskはRunnableFutureインタフェースを実現見ることができます。
2.3 RunableFutureインタフェース
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
我々は呼び出し可能であるプラスのRunnableのバージョンと言うなぜ私たちが知っている前に、こちらを参照してください。実際には、いくつかの最適化はRunnableをに基づいて行われます。
2.4、Runnableインタフェース
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
あまりにもありますので、これを対処する前に、あまりここでは説明されていません。
2.5今後のインタフェース
クラスまたはインタフェースのビューのすべてのメソッド(考え使用ALT + 7)によって
- 方法キャンセル:計算が終了していないが、演算処理をキャンセルすることができ、
- isCancelled方法:キャンセルするかどうか
- isDone方法:完了
- getメソッド:結果は(計算終了していない場合、また待たなければなりません)を取得
- 指定された時間内に、結果は返されません、TimeOutExceptionの例外をスローする場合は(長い、TimeUnitで)結果を得るには、あなたは、タイムアウトを指定することができます取得
2.6 FutureTaskソースコード解析
コードを通じて、我々はわずかに渡し、パラメータとして、FutureTask、呼び出し可能なオブジェクトインスタンスのコンストラクタを呼び出すことがわかります。
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
あなたが呼び出し可能なスローNullPointerExceptionが渡さない場合。我々は、状態変数の値NEWがあることがわかりました
/*
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
- NEW(初期化)
- (動作)を完了
- NORMAL(完成状態)
- EXCEPTIONAL(異常終了に伴うタスク)
- CANCELED(まだ呼び出しで実行されないキャンセルする(true)メソッドをキャンセル)
- 中断(通話上で実行すると(true)メソッドがキャンセルされ、キャンセル)
- INTERRUPTED(解除状態は、遮断が中断換算)
ソースコメント部、複数のタスクの状態の変化です。
FutureTask通常直接主題、スレッドクラスの着信のコンストラクタメソッドへのパラメータとして。
NEWの下で通常の状況- >補完----------------- - > NORMAL
呼び出し新しいFutureTask新規ステータスは
FutureTaskを補完-----------------変更runメソッドを呼び出します
途中、珍しいことではありませんrunメソッドを実行した後、それはNORMALに戻ります
- コールtask.getは、実行スレッドの結果を得ることができます
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
このタスクはすでに動作しているかどうかを判断するために、識別操作を完了、すでにrunメソッドを呼び出しています。説明タスクが完了していない、私たちはそうここawaitDoneメソッドを呼び出し、待つ必要があります。
- 結果は、メソッド呼び出しのレポートです
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
ステータスは(NORMAL)、業績への直接の復帰を完了した場合。
追伸
社長によると、理解した上でソースコード解析が発見されていない、呼び出し可能なソースコードを探る、我々が思ったほど難しいことではありません。ソースコード解析の各ステップは、それがライン上にあるかのインとアウトを知って、理解していません。
GitHubのプログラム猿協会は、歓迎スター
https://github.com/ITfqyd/cxyxsを
対応するトピックを形成するために、この記事では、githubのに記録されています。