スレッドを使用するシナリオ - スレッド同時実行の安全性の原因と解決策

コンピュータを購入するとき、コンピュータの CPU に搭載されているコアとスレッドの数に特に注意を払うことがよくあります。これはしばしばコンピュータの速度を決定するため

、これはすべてタスクマネージャーで見つけることができます。

 

現時点では、マルチスレッド操作にさらされていても、スレッドとは何かについて疑問を持っているかもしれません。

Baidu Encyclopedia によると、スレッド(英語: スレッド) は、オペレーティング システムが操作のスケジューリングを実行できる最小単位ですこれはプロセスに含まれ、プロセス内の実際の作業単位です。スレッドとは、プロセス内の単一の順次制御フローを指します。プロセス内で複数のスレッドを同時に実行でき、各スレッドが異なるタスクを並行して実行します。Unix System V やSunOSでは、軽量プロセス (軽量プロセス) とも呼ばれますが、軽量プロセスはカーネル スレッド (カーネル スレッド) を指し、ユーザー スレッド (ユーザー スレッド) はスレッドと呼ばれます。

では、いつマルチスレッドを使用する必要があるのでしょうか?

1 : 複数の異なるタスクを同時に処理する
たとえば、ビデオ会議システム:
1 : 音声を送信
2 : ビデオを送信する
3 : デスクトップを共有する
2 : 複数の同じタスクを同時に処理する ( 並行性とも呼ばれる )
小玉 5000
1 : 1 つのスレッドが、ボールの描画や移動などのすべての操作をポーリングします
ボール数が増えている場合:ポーリングに時間がかかる
これらのボールを処理するためのマルチスレッド:
1 つのスレッドが担当するのは一部だけです。たとえば、スレッドは 1000 回しか実行されません。
3: パイプライン モード
を持つ完全なクエストチェーン
タスク 1 :
タスク 2 : タスク 1 を完了する必要があります
タスク 3 : タスク 2 を完了する必要があります

そうすることで、各スレッドを最も効率的に使用できます。

では、スレッド同時実行の安全性とは何ですか?

並行タスクを処理する場合、複数のスレッドが同じリソースで動作するため、動作時間がずれず、メモリ内の動作が繰り返され、データが混乱し、セキュリティ上の問題が発生します。

 例: スレッドごとにタスクを配置しました。つまり、num に 1000 回を追加します。

スレッド スタック操作の手順: ヒープ メモリから num を取得します -->> num のコピーをスレッド スタックにコピーします -->> num++ 操作を実行します

——>>num を返し、ヒープメモリの num に代入します。

これは順調に進んでいるように見えますが、必ずしも 1 つのスレッドだけが同時にヒープ メモリから num を取得するとは限らないことに注意してください。

複数のスレッドが取得した場合、num++ 操作が繰り返されるため、最終的な数値が 3000++ 未満になり、データが間違っています。

 一般的な状況:

1 : 読み取りと読み取りは、スレッド セーフの問題を引き起こしません。
2: 読み取りと書き込みが生成されます
3 : ライト ライトが生成されます

そして、この問題をどのように解決しますか?

結局のところ、このデータが銀行の金額を表しているのであれば、それが間違っているのは望ましくありません! ! !

ロックの使用 (同期) :

コード ブロックを同期し、リソースをロックし、現在モニター ロックを保持しているスレッドのみがリソースにアクセスできるようにする

スレッドが num をヒープ メモリにコピーすると、ヒープ メモリが一時的に「ロック」され、アクセスできなくなります。

スレッドが num の操作を完了し、ヒープ メモリに num を割り当てた場合にのみ、スレッドは「ロック解除」され、他のスレッドが引き続きヒープ メモリへのアクセスを競合できるようになります。

これにより、操作が繰り返されず、データが間違っていないことが保証されるだけでなく、同時に、競合アクセスメカニズムにより、タスクの速度が大幅に加速されます。

例は次のとおりです。

タスク クラス:

public class Task{

     static int num=0;//静态变量,处于堆内存中

    public static void main(String[] args) {

        Task tt = new Task();
        Thread t1=new Thread(new Threadsy(tt));
        t1.start();
        Thread t2=new Thread(new Threadsy(tt));
        t2.start();
        Thread t3=new Thread(new Threadsy(tt));
        t3.start();//创建并启动三个线程

        try {
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
            throw new RuntimeException (e);
        }//阻塞,直到线程全部完成,便于得到最终结果

        System.out.println(tt.num);//检验结果
        
    }
}

スレッドクラス:

public class Threadsy implements Runnable {

    Task tt = new Task();
    public Threadsy(Task tt) {
        this.tt = tt;
    }//构析方法,便于取堆内存中的num。

    static Object object = new Object();//值得注意的是,Object要保证是静态变量,存在堆内存中,才可以通过它“锁住”堆内存的num

    public void run() {
            for (int i = 0; i < 1000; i++) {

                synchronized (object/*只能“锁”对象*/) {
                    tt.num++;
                }//给堆内存上锁,保证线程安全

        }
    }//线程操作方式
}

結果は次のとおりです。

すべてが正常です!! !

 

そして、リソース ロックを削除すると、次のようになります。

すなわちデータエラー:

並行タスクの場合、マルチスレッドを使用すると効率が大幅に向上しますが、スレッドの安全性の問題に十分注意してください。

 

おすすめ

転載: blog.csdn.net/AkinanCZ/article/details/126058188