ホームページ 类库下载 java类库 Java 同時実行の基本の概要

Java 同時実行の基本の概要

Nov 02, 2016 am 10:41 AM
java

同時実行性とは、複数のプログラムを並行して実行する、またはプログラムの複数の部分を並行して実行する機能です。プログラム内の時間のかかるタスクを非同期または並列で実行できれば、プログラム全体のスループットと対話性が大幅に向上します。最近の PC には複数の CPU または 1 つの CPU 内に複数のコアが搭載されており、複数のコアを適切に使用できるかどうかが、大規模なアプリケーションの鍵となります。

スレッドの基本的な使い方

スレッドの実行中に実行されるコードを記述する方法は 2 つあります。1 つは Thread サブクラスのインスタンスを作成して run メソッドをオーバーライドする方法、もう 1 つはスレッドの実行時に Runnable インターフェイスを実装する方法です。クラスを作成しています。もちろん、Callableを実装するという手もありますが、CallableとFutureの組み合わせではタスク実行後に戻り値を取得できますが、RunnableメソッドやThreadメソッドはタスク実行後に結果を取得できません。

public class ThreadMain {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        new Thread(myThread).start();

        new MyThreas2().start();
    }
}

// 第一种方式,实现Runable接口
class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println("MyThread run...");
    }
}

// 第二种方式,继承Thread类,重写run()方法
class MyThreas2 extends Thread {
    @Override
    public void run() {
        System.out.println("MyThread2 run...");
    }
}
ログイン後にコピー

スレッドが開始されると、start()メソッドは、runメソッドが別のCPUで実行されたかのように、run()メソッドの実行完了を待たずにすぐに戻ります。

注: スレッドを作成して実行するときによくある間違いは、以下に示すように、start() メソッドの代わりにスレッドの run() メソッドを呼び出すことです。 .run (); // start(); である必要があります


run() メソッドは実際に期待どおりに呼び出されるため、最初は何も違和感はありません。ただし、実際には、 run() メソッドは作成されたばかりの新しいスレッドによって実行されるのではなく、現在のスレッドによって実行されます。つまり、上記の 2 行のコードを実行するスレッドによって実行されます。作成した新しいスレッドで run() メソッドを実行したい場合は、新しいスレッドの start メソッドを呼び出す必要があります。

Callable と Future を組み合わせて、タスク実行後の戻り値を実現します:

public static void main(String[] args) {
    ExecutorService exec = Executors.newSingleThreadExecutor();
    Future<String> future = exec.submit(new CallTask());

    System.out.println(future.get());
}
class CallTask implements Callable {
    public String call() {
        return "hello";
    }
}
ログイン後にコピー

スレッド名をスレッドに設定します:

MyTask myTask = new MyTask();
Thread thread = new Thread(myTask, "myTask thread");

thread.start();
System.out.println(thread.getName());
ログイン後にコピー

スレッドを作成するときに、スレッドに名前を付けることができます。これは、異なるスレッドを区別するのに役立ちます。

volatile

マルチスレッド同時プログラミングでは、synchronized と volatile の両方が重要な役割を果たし、Volatile はマルチプロセッサ開発における共有変数の「可視性」を保証します。可視性とは、あるスレッドが共有変数を変更すると、別のスレッドが変更された値を読み取ることができることを意味します。場合によっては、synchronized よりもコストが低くなりますが、volatile では変数のアトミック性を保証できません。

揮発性変数が書き込まれるとき(アセンブリの下にロック命令がある)、マルチコア システムではロック命令には 2 つの機能があります:

現在の CPU キャッシュ ラインをシステム メモリに書き戻す。

このライトバック操作により、他の CPU によってキャッシュされたデータがアドレスを変更して無効になります。

マルチCPUはキャッシュ一貫性の原則に従っており、各CPUはバス上で送信されるデータを傍受することによってキャッシュ値が期限切れになっているかどうかをチェックし、キャッシュに対応するメモリアドレスが変更されていることが判明すると、対応するキャッシュラインが更新されます。無効ステータスに設定されると、次のデータ操作がシステム メモリから再読み取りされます。 Volatile についてさらに詳しく知りたい場合は、ここをクリックして Volatile の実装原理の詳細な分析をご覧ください。

synchronized

Synchronized は常にマルチスレッド同時プログラミングのベテランです。しかし、Java SE1.6 では Synchronized がさまざまに最適化されており、場合によってはそれほど重くなくなりました。 。

Java のすべてのオブジェクトはロックとして使用できます。スレッドが同期されたコード ブロックにアクセスしようとするときは、まずロックを取得し、終了するか例外をスローするときにロックを解放する必要があります。

同期メソッドの場合、ロックは現在のインスタンス オブジェクトです。

静的同期メソッドの場合、ロックは現在のオブジェクトの Class オブジェクトです。

同期メソッドブロックの場合、ロックは同期ブラケットで設定されたオブジェクトです。

synchronizedキーワードは継承できないということは、基本クラスのsynchronizedメソッドがサブクラスではデフォルトで同期されないことを意味します。スレッドが同期されたコード ブロックにアクセスしようとすると、まずロックを取得し、終了するか例外をスローするときにロックを解放する必要があります。 Java のすべてのオブジェクトはロックとして使用できます。では、ロックはどこにあるのでしょうか?ロックは Java オブジェクト ヘッダーに格納されます。オブジェクトが配列型の場合、仮想マシンはオブジェクト ヘッダーの格納に 3 ワード (ワード幅) を使用します。オブジェクトが非配列型の場合、仮想マシンは 2 ワードを使用します。 (ワード幅) オブジェクトヘッダーを格納します。同期に関するさらに詳しい情報については、「Java SE1.6 での同期」をクリックしてください。

スレッドプール

スレッドプールはワーカースレッドの管理を担当し、実行を待っているタスクのキューが含まれています。スレッドプールのタスクキューはRunnableの集合であり、ワーカースレッドはタスクキューからRunnableオブジェクトを取り出して実行する役割を担います。

ExecutorService executor  = Executors.newCachedThreadPool();for (int i = 0; i < 5; i++) {
    executor.execute(new MyThread2());
}
executor.shutdown();
ログイン後にコピー

Java は Executor を通じて 4 種類のスレッド プールを提供します:

newCachedThreadPool: 新しいタスクの場合、アイドル状態のスレッドがない場合、アイドル状態のスレッドが一定の時間を超えると、新しいスレッドが作成されます。リサイクルされることになります。

newFixedThreadPool:创建一个固定数量线程的线程池。

newSingleThreadExecutor:创建一个单线程的线程池,该线程池只用一个线程来执行任务,保证所有任务都按照FIFO顺序执行。

newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。

  以上几种线程池底层都是调用ThreadPoolExecutor来创建线程池的。

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
ログイン後にコピー

corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。

maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。

keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。

TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。,可以选择的阻塞队列有以下几种:

workQueue(任务队列):用于保存等待执行的任务的阻塞队列。

 


ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。

LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。

PriorityBlockingQueue:一个具有优先级得无限阻塞队列。

当提交新任务到线程池时,其处理流程如下:

先判断基本线程池是否已满?没满则创建一个工作线程来执行任务,满了则进入下个流程。

其次判断工作队列是否已满?没满则提交新任务到工作队列中,满了则进入下个流程。

最后判断整个线程池是否已满?没满则创建一个新的工作线程来执行任务,满了则交给饱和策略来处理这个任务。


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルの量を見つけるためのJavaプログラム カプセルの量を見つけるためのJavaプログラム Feb 07, 2025 am 11:37 AM

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Feb 07, 2025 pm 12:11 PM

Spring Bootは、Java開発に革命をもたらす堅牢でスケーラブルな、生産対応のJavaアプリケーションの作成を簡素化します。 スプリングエコシステムに固有の「構成に関する慣習」アプローチは、手動のセットアップを最小化します。

See all articles