最終的にはマルチスレッドのアプローチはいくつかありますか?
JAVAマルチスレッドの実装では、オンラインや書籍が異なる意見を持っているかどうか、いくつかの2つを言うために、いくつかのは4、ちょうどBaiduは、我々は答えの様々を見ることができますがありますと言います。
それは本当に、いくつかの一つですか?のは、APIドキュメントのJAVAを見てみましょうします。https://docs.oracle.com/javase/9/docs/api/java/lang/Thread.html
私たちは、はっきり文書から見ることができる、マルチスレッド、2つの方法がありますが、1注文でクラス宣言のサブクラスでThread
、ステートメントの実現があるRunnable
インタフェースクラス。
2つの実装を比較します
実行可能なインタフェースを実装します。
/**
* @author Chen
* @Description 使用runnable接口实现多线程
* @create 2019-11-04 21:38
*/
public class RunnableStyle implements Runnable{
public static void main(String[] args) {
Thread thread = new Thread(new RunnableStyle());
thread.start();
}
@Override
public void run() {
System.out.println("使用runnable接口实现多线程");
}
}
Threadクラスの継承:
/**
* @author Chen
* @Description 使用Thread方式实现多线程
* @create 2019-11-04 21:41
*/
public class ThreadStyle extends Thread{
public static void main(String[] args) {
Thread thread = new ThreadStyle();
thread.start();
}
@Override
public void run() {
System.out.println("使用Thread类实现多线程");
}
}
Runableを使用するか、スレッド?
彼らはマルチスレッド達成することができますので、我々はカジュアル作成する実用的な方法を選択するために使用するか、それができなければなりませんか?
答えは達成することであるRunable
ずっといい。
主な理由は次のとおりです。
1. デカップリング観点、マルチスレッドタスクの実行されるべきである(すなわち、実行方法の内容である)Thread
クラスが切り離され、
むしろ、彼らは一緒に書かれていません。
2.継承を使用している場合はThread
、我々は新しいタスクを作成するたびにのみ、別のスレッドを作成することができ、マルチスレッドを実装するクラスを、そしてこの損失が比較的大きい、我々はそうで作成、破棄してする必要があります。使用するRunnable
インタフェースは、その後のフォローアップは、我々は、スレッドプールを使用することができますので、あなたができる新しいスレッドによる損失を減らします。
3. JAVAは単一継承なので、一度は継承されたThread
他のクラスに継承することができなくなり、プログラムのスケーラビリティを制限します。
Runableスレッドは、スレッドとの違いを作成するには?
使用しRunable
、我々が使用している作成する方法をThread
、パラメータを使用してコンストラクタクラスThread
を作成する方法を、の使用であり、Thread
引数なしでクラスのコンストラクタは、これらのメソッドの両方を書き換えるRun
のは、見てみましょう、この方法を参照Thread
Runメソッドクラスは、達成するためにどのようにされています。
/* What will be run. */
private Runnable target;
/**
* If this thread was constructed using a separate
* <code>Runnable</code> run object, then that
* <code>Runnable</code> object's <code>run</code> method is called;
* otherwise, this method does nothing and returns.
* <p>
* Subclasses of <code>Thread</code> should override this method.
*
* @see #start()
* @see #stop()
* @see #Thread(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
if (target != null) {
target.run();
}
}
これらは、の一部であるThread
クラスのソースコードは、我々が実行見ることができるrun
方法の時間を、それが最初の着信かどうかを決定するRunable
渡された場合、インタフェースの実装クラスインターフェースの実装クラスのrun
メソッドを渡されない場合、直接実行されますサブクラスは、オーバーライドrun
メソッドをので、本質的に、これら2つの方法の本質は、実装されているRun
方法が、Run
異なるソース方法から。
神話
スレッドプールのスレッドを作成すると、新しいスレッドの方法とみなすことができます
/**
* @author Chen
* @Description 使用线程池创建线程
* @create 2019-11-05 9:40
*/
public class ThreadPoolStyle {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i <1000 ; i++) {
executorService.submit(new Task());
}
}
static class Task implements Runnable{
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
以下は、簡単に見ているexcutors
内部スレッドを作成する方法:
あなたは、新しいスレッドコードスレッド・プールには、以下を渡すことで内部を見ることができRunnable
、その後、new thread
外装には、作成した方法が同じではないように見えますが、原理は通過であるもののので、作成するために、Runnable
マルチスレッドインタフェースを実現します。
/**
* The default thread factory
*/
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
FutureTaskを通じて呼び出し可能と作成のスレッドが新しいスレッドの方法とみなすことができます
よるCallable
とFuture
:
/**
* @author Chen
* @Description 使用Callable、Future以及FutureTask
* @create 2019-11-05 10:03
*/
public class FutureTaskStyle {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
Future<String> future = executorService.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(500);
return "future result";
}
});
System.out.println(System.currentTimeMillis());
System.out.println(future.get());
System.out.println(System.currentTimeMillis());
}
}
よるCallable
とFutureTask
:
/**
* @author Chen
* @Description 使用Callable、Future以及FutureTask
* @create 2019-11-05 10:03
*/
public class FutureTaskStyle {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
FutureTask<String> futureTask = new FutureTask<String>(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(500);
return "future result";
}
});
new Thread(futureTask).start();
System.out.println(System.currentTimeMillis());
System.out.println(futureTask.get());
System.out.println(System.currentTimeMillis());
}
}
使用ctrl+alt+u
ビューのFutureTask
継承グラフ:あなたが見ることができますRunableFuture
継承Future
やRunnable
インターフェース、FutureTask
だけでなく、実現RunableFuture
するので、FutureTask
また間接的に実装Runable
インターフェイスを。したがって、この方法および使用Runnable
の原則を達成するための方法は同じです。
タイマーにより、
/**
* @author Chen
* @Description 使用定时器创建新的线程
* @create 2019-11-05 10:26
*/
public class TimmerStyle {
public static void main(String[] args) {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
},1000,1000);
}
}
見てTimerTask
も実装Runnable
インタフェースは、本質的には、それが使用するRunnable
インターフェイスを作成します。
匿名内部クラスまたはラムダ式で
/**
* @author Chen
* @Description 使用匿名内部类 和lamada表达式实现多线程
* @create 2019-11-05 10:36
*/
public class AnonymousInnerClassStyle {
public static void main(String[] args) {
//匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}).start();
//Lambda 表达式
new Thread(()-> System.out.println(Thread.currentThread().getName())).start();
}
}
この形式は、単に構文が効果を達成するために、実際には、匿名内部クラスとラムダ式を少し変更と同じですが、交換の文言れます。
概要
マルチスレッド終了にはいくつかの方法がありますか?別の観点からは、ビューのマルチスレッドの性質の点の実現から、異なる答えが存在するであろう、二つあり、一つは達成することでRunnable
、一方が継承されるインターフェースThread
クラスとコード実装レベルから、多くがあり、そのようなスレッドプール、などFutureTask
匿名内部クラスとLambda
表現。
実際には、原則を見ては、と呼ばれ、自然の中で2つの実装では同じであるThread
クラスのrun
メソッド、およびrun
、着信があれば方法は、裁判官を持っているrunnable
の実装に、空ではないrun
方法で自分自身内のコード。
通常の状況下で、我々は、使用するRunable
主に次のような理由から、新しい道を通すためのインタフェースを:
結合の表示、タスクのコード提出するの手続き点からThread
クラスコードが低いカップリングから分離されます。
観点からJavaは単一継承であるため、継承の使用、拡張することができるThead
方法は、クラスは、プログラムのクラスの拡張を低減する、他の基本クラスに継承することができません。
ビューのリソース消費ポイントの観点から、使用Runnable
我々は、スレッドプールのスレッドを管理するために使用できる方法は、新しいスレッドがスレッドや他の資源の枯渇に起因する破壊を減らすことができます。