マルチスレッドと並列プログラミング

Runnable オブジェクト: タスクとして理解でき、Runnable インターフェイスのインスタンスです。

スレッド: タスクの最初から最後までの実行プロセスであり、本質的にはタスクの実行を容易にするオブジェクトです。

スレッド状態: スレッド状態は、オペレーティング システムのスレッド ライフ サイクルの段階です。

プロセス: メモリ内で実行されるアプリケーション。プロセス内で複数のスレッドを開始できます。

タスク クラスには通常、タスクのステータスと動作を記述するために使用できるいくつかの属性とメソッドが含まれています。

以下はタスククラスを定義してスレッドを作成する例です。

public class Task implements Runnable {
    private String name;
    public Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        // 执行任务
        System.out.println("Executing task: " + name);
    }

    public static void main(String[] args) {
        // 创建一个任务
        Task task = new Task("Task 1");
        // 创建一个线程来执行任务
        Thread thread = new Thread(task);
        // 启动线程
        thread.start();
    }
}

start メソッドを呼び出した後、run メソッドは Thread がデフォルトで実行する通常のメソッドになります。

テストだと思うのですが…

プログラムエラー修正

1.forFun クラスは Runnable インターフェイスを実装しますが、 forFun コンストラクターで新しい forFun オブジェクトを作成し、それを新しいスレッドで実行しようとします。ただし、この新しい オブジェクトは インターフェイス forFun を実装していないため 、 コンストラクター に次のように渡す ことはできません。RunnableRunnableThread

public class forFun implements Runnable {
    public static void main(String[] args) {
        new forFun();
    }
    public forFun(){
        new Thread(this).start();
    }

    @Override
    public void run() {
        System.out.println("1");
    }
}

このようにしてテストは5回出力されます

2. start を 2 回呼び出します

各スレッドは 1 回だけ開始できます。開始を削除するだけです。

Platform.runLaterを使用する目的は何ですか?

Runnable オブジェクトをアプリケーション スレッドで実行するようにシステムに指示します。

★スレッドのステータス (これはテストする必要があります)

  1. New : スレッドが作成されてもまだ実行を開始していない場合、スレッドは新しい状態になります。

  2. Runnable : スレッドは実行の準備ができていますが、CPU スケジューリングを待っている可能性があります。

  3. 実行中: スレッドは CPU 上で実行されています。

  4. Blocked : スレッドはイベント (I/O 操作の完了など) を待っているため、実行を一時的に停止し、イベントが発生するのを待ちます。

  5. 待機中: スレッドは別のスレッドが操作を実行するのを待っています。

  6. 時間制限付き待機: スレッドは別のスレッドによる操作の実行を待機していますが、時間制限があります。

  7. 終了: スレッドは実行を完了したか、他のスレッドによって中断されました。

        新しいスレッドを作成すると、最初は新しい状態になります。次に、start() メソッドを呼び出すと、スレッドが実行を開始し、Runnable 状態に入ります。CPU スケジューラがこのスレッドの実行を選択すると、実行状態になります。スレッドが動作中に待機する必要があるイベント (I/O 操作など) に遭遇すると、ブロック状態になります。待機中のイベントが完了すると、スレッドは再び実行可能状態に入り、CPU スケジューラの選択を待ちます。アクティブに待機している場合は待機状態に入り、目覚めるのを待ってから再び実行可能状態に入ります。アクティブにスリープしている場合は時間待機状態になり、スリープ時間が経過すると実行可能状態になります。実行状態が異常中断された場合、または実行が完了した場合、デッドフェーズに入ることに注意してください。

(写真をご覧いただくと理解が深まります。上記は私なりのまとめです)

スレッド プールを使用する利点は何ですか?

スレッド プールを使用すると、スレッドを効果的に管理およびスケジュールし、システムの同時実行パフォーマンスを向上させることができ、同時にシステム リソースを効果的に管理し、システム リソースの枯渇を回避し、システムの安定性と応答性を向上させることができます。

ロック

同期ロックとリエントラントロックの2種類に分かれる ReentrantLock

1. 同期ロック

public class LockExample {
    private final Object lock = new Object();

    public void method() {
        synchronized (lock) {
            // 这里是临界区,只有一个线程可以进入
            // 其他线程需要等待这个线程释放锁
        }
    }
}

2. リエントラントロック

 同じスレッドがこのロックを複数回取得できます。ただし、デッドロックを避けるために、時間内にロックを解放することを忘れないでください。

import java.util.concurrent.locks.ReentrantLock;

public class LockExample {
    private final ReentrantLock lock = new ReentrantLock();
    public void method() {
        lock.lock();
        try {
            // 这里是临界区,只有一个线程可以进入
            // 其他线程需要等待这个线程释放锁
        } finally {
            lock.unlock();
        }
    }
}

別の記述方法もあります

1.プライベート静的ロック lock=new ReentrantLock(); を構築します。

2.lock.lock()を取得する

3. lock.unlock() を解放します。 

4. ロック条件の作成 lock.newCondition()

await() はロックを解放し、スレッドを一時停止します。条件が満たされると、起動して再びロックを取得します。

signal()/signalAll():condition.await() の FIFO キュー内の最初のノード (またはすべて) をウェイクアップします。

デッドロック:実行中にリソースの奪い合いにより複数のプロセスが待ち合い、外部からの力がなければ先に進めなくなる現象。

デッドロックを回避する方法: 各スレッドのロック順序が同じになるようにリソースのソートを実装します。

 入出金の手順に関するテストを受ける必要があります(詳細は後ほど)。

 入金タスクは、残高が変化するたびに出金タスクに通知します。出金タスクが起動された時点でも、条件(残高<金額)の判定結果が真である可能性があります。if ステートメントを使用すると、出金タスクで不正な出金が行われる可能性があります。

wait() メソッドは、if ステートメントではなくループ内で使用する必要があります。修正後は異常事態のみ待機が覚醒するようになる。

synchronized(object){
    while(!condition){
        try{
            object.wait();
        }
        catch(InterruptedException ex){
            // 处理异常
        }
    }
}

バッファクラス 

 

通常、Buffer クラスの読み取りと書き込みは、データの正確性と一貫性を確保するためにシングルスレッド環境で呼び出されます。

読み取りメソッドが呼び出されたときにキューが空の場合、読み取りメソッドは新しいデータが読み取れるまで待機します。

write メソッドが呼び出されたときに、キューがいっぱいの場合、キューに新しいデータを保存するのに十分なスペースができるまで、write メソッドもブロックされます。

ブロックキュー 

(1) ブロッキング キュー: ブロッキング挿入および削除メソッドをサポートする 2 つの追加操作をサポートするキュー。

ブロッキングキューはスレッドセーフなキューアクセス方法です

ブロッキング キューが要素を挿入する必要がある場合、キューがいっぱいの場合、スレッドはキューがいっぱいになるまでブロックされます。

ブロッキング キューが要素を削除する必要がある場合、キューが空の場合、スレッドはキューが空でなくなるまでブロックされます。

(2) Java でサポートされるブロッキング キュー:

配列ブロックキュー

LinkedBlockingQueue

優先ブロッキングキュー

 セマフォ

创建:セマフォ semaphore = new Semaphore(3);

セマフォを取得します: Semaphore.acquire();

セマフォを解放します: Semaphore.release();

ロックは 1 つの共有リソースのみをロックでき、セマフォは複数の共有リソースをロックできます。

=>セマフォは複数のリソースへのアクセスを制御するために使用され、ロックは 1 つのリソースへのアクセスを制御するために使用されます。

同期コレクション

同期されたコレクション: スレッドセーフなコレクションを実装します。

ArrayList は同期されていません。synchronizedList を実装して同期させます。

 フォーク/ジョイン

抽象クラスです

フォーク/結合フレームワーク: フォーク分割と結合マージ。並列タスクを実行し、大きな問題をサブ問題に分割するために使用されます。

意味:

パブリック抽象クラス ForkJoinTask<V> は Future<V> を実装し、Serializable{ }

V: タスクの実行結果の種類

Future<V>: ForkJoinTask が Future インターフェイスを実装しているため、タスクの実行結果を取得するために使用できることを示します。

RecursiveAction (値を返さないタスク用) と RecursiveTask (値を返すタスク用) は、ForkJoinTask の 2 つのサブクラスです。

楽しみのために、フォークプール

RecursiveAction mainTask = new SortTask(list);
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(mainTask);

1000 個のスレッドを開始するための同期ロック Synchronized が含まれるサンプル コード。各スレッドは初期値 0 の変数 sum に 1 を加算します。

import java.util.concurrent.*;
 
public class forFun {
    private Integer sum = new Integer(0);
    public static void main(String[] args) {
        forFun test = new forFun();
        System.out.println("What is sum ? " + test.sum);
    }
 
    public forFun() {
        synchronized(this){//同步代码块,确保只有一个线程可以访问以下代码
            ExecutorService executor = Executors.newFixedThreadPool(1000);//创建大小1000 的线程池
            for (int i = 0; i < 1000; i++) {
                executor.execute(new SumTask());//将SumTask交给线程池
            }
            executor.shutdown();
            while(!executor.isTerminated()) {//等待任务完成
            }
        }
    }
    class SumTask implements Runnable {// 定义一个实现Runnable接口的SumTask类
        public void run() {
            synchronized(this){// 同步代码块,确保只有一个线程可以访问以下代码
                int value = sum.intValue() + 1;
                sum = new Integer(value);
            }
        }
    }
}

楽しく遊ぼう、口座入出金業務

スレッド プールと同期ロックがあります。lz はブロックチェーンのメンターと一緒に仕事をしていて、Solidity を使って毎日このようなことを書いていました。それを見たとき、私はとても優しくて幸せな気持ちになりました。

import java.util.concurrent.*;

public class forFun {
    private static Account account = new Account();
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2); // 创建固定大小为2的线程池
        executor.execute(new DepositTask());
        executor.execute(new WithdrawTask());
        executor.shutdown();
        System.out.println("Deposit Task\t\tWithdraw Task\t\tBalance");
    }

    // 存款任务
    public static class DepositTask implements Runnable {
        public void run() {
            try {
                while (true) {
                    account.deposit((int) (Math.random() * 10) + 1);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

    // 取款任务
    public static class WithdrawTask implements Runnable {
        public void run() {
            while (true) {
                account.withdraw((int) (Math.random() * 10) + 1);
            }
        }
    }

    // 账户类
    public static class Account {
        private int balance = 0;

        // 获取账户余额
        public int getBalance() {
            return balance;
        }

        // 存款方法,使用 synchronized 保证线程安全
        public synchronized void deposit(int amount) {
            balance += amount;
            System.out.println("Deposit " + amount +
                    "\t\t\t\t\t" + getBalance());
            notifyAll(); // 唤醒其他等待线程
        }

        // 取款方法,使用 synchronized 保证线程安全
        public synchronized void withdraw(int amount) {
            try {
                while (balance < amount)  // 当余额不足时,进入等待状态
                    wait();
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }

            balance -= amount;
            System.out.println("\t\t\tWithdraw " + amount +
                    "\t\t" + getBalance());
        }
    }
}

おすすめ

転載: blog.csdn.net/mynameispy/article/details/135306516