Javaスレッドプローブ

24602 ワード

まず、スレッドとプロセスとは何かを復習します.アプリケーションがメモリにロードされ、実行の準備ができたら、プロセスが作成されたと言います.プロセスは、独立した機能を持つプログラムであり、あるデータセットについて前回実行されたアクティビティであり、プロセスはシステムがリソースの割り当てとスケジューリングを行う独立した単位である.スレッドはプロセスの1つのエンティティであり、CPUのスケジューリングと割り当ての基本単位であり、プロセスがより小さく独立して実行できる基本単位である.スレッドには独自のシステムリソースがなく、1つのプロセスの複数のスレッド共有オペレーティングシステムが各プロセスのリソースを割り当てます.1つのスレッドと1つの作成と別のスレッドの取り消しは、同じプロセス内の複数のスレッド間で同時に実行できます.実行可能なプログラムには少なくとも1つのプロセスがあり、1つのプロセスには少なくとも1つのスレッドがあります.論理的に言えば、マルチスレッドは、1つのアプリケーションの複数の実行部分が同時に実行できることを意味する.しかし、システムは複数のスレッドを独立したアプリケーションと見なしてリソースを割り当てておらず、システムリソースの割り当てとスケジューリングの基本単位はスレッドである.これがプロセスとスレッドの重要な違いです.
スレッドのステータス
オペレーティングシステムでは、スレッドには通常、wait、blocked、running、deadの4つのステータスがあります.OSはキューとしてスレッドを維持し,新たに確立したスレッドがキューの終端に追加され,キューヘッダからスレッドが取得され,スレッドのCPUタイムスライスが終了すると,そのスレッドはキューのキューの終端に返される.
デーモンスレッドと非デーモンスレッド
Javaには2種類のスレッドがあります:1、デーモンスレッド;2、非デーモン(ユーザー)スレッド.彼らの違いは、親スレッドが作成したデーモンスレッドが親スレッドが終了すると、デーモンスレッドが自動的に終了することです.親スレッドが作成した非デーモンスレッドは、親スレッドが終了したときも生存します.プロセスにとって、スレッドが生きている限り、このプロセスも生きています.Javaアプリケーションごとに、少なくとも1つの非デーモンスレッド、すなわちプライマリスレッドがあります.ユーザーがアプリケーションを閉じると、プライマリ・スレッドが死亡します.ただし、プログラムが他の非デーモンスレッドを作成した場合、メインプロセスは存続します.
スレッドの作成
Javaプログラムでスレッドを作成するには、1、implements Runnableインタフェース、2、extends Thread類;3、ThreadGroupクラスで実現する.
class ThreadA implements Runnable{
    ......
    @Override
    public void run(){
        .....
    }
}

class ThreadB extends Thread{
    .......
    @Override
    public void run(){
        ....
    }
}

public class ThreadSample{
    public static void main(String[] args){
        Thread sampleA = new Thread(new ThreadA());
        sampleA.start();
        Thread sampleB = new ThreadB();
        sampleB.start();
    }
}
以上は最も一般的な2つのスレッドの作成方法であり、run()メソッドではスレッドが完了するトランザクションを記述することができます.Runnableインタフェースを実装することは、Threadクラスメソッドを継承することよりも優れている.
このとき、マルチスレッドではなく、1つのスレッドしか作成されません.
スレッドの基本操作
deamon/non-deamonプロパティの起動/停止スレッドの停止/回復スレッドを設定stopメソッドを呼び出すと、スレッドが停止する可能性があります.supendメソッドを呼び出すとスレッドが保留される可能性があります.resumeメソッドを呼び出すと、別の実行プログラムが保留中のスレッドを復元できます.しかし、これらの方法はJ 2 SEから捨てられた.デッドロックを起こしやすいからだ.譲歩操作yieldメソッドは、他の実行スレッドに対してobjが呼び出されるのを待つ.wait()メソッドでは、スレッドがオブジェクトの通知を待っている可能性があります.objは、現在のスレッドが望む待機オブジェクトのみを望んでいる.中断/邪魔スレッドの3つの方法:interrupt、isInterrupted、interrupted.
スレッド同期
以上は、スレッドとスレッドを作成するためのいくつかの基礎知識にすぎず、マルチスレッドには関連していません.もし2かごがあれば、2人はとても退屈な人が反対のことをしていて、1つはボールを左側の山から右側に移して、もう1つは反対です.通常、この二人が十分遊んだ後の2つのボールの総数は変わらないはずだ.1つのスレッドで1人をシミュレートします.プログラムは次のとおりです.
public class BucketBallGame{
    private int bucket[] = {10000, 10000};
    private static boolean RIGHT_TO_LEFT;

    public static void main(String[] args){
        new BucketBallGame().doTransfers();
    }

    private void doTransfers(){
        for(int i=0; i < 10; i++){
            new Thread(new TransferThread(!RIGHT_TO_LEFT)).start();
            new Thread(new TransferThread(RIGHT_TO_LEFT)).start();
        }
    }

    public void transfer(boolean direction, int numToTransfer){
        if(direction == RIGHT_TO_LEFT){
            bucket[0] += numToTransfer;
            bucket[1] -= numToTransfer;
        }else{
            bucket[0] -= numToTransfer;
            bucket[1] += numToTransfer;
        }
        System.out.println("Bucket_Right: "+bucket[0]+" Bucket_Left: "+bucket[1]+" Total: "+(bucket[0]+bucket[1]));
    }


    private class TransferThread implements Runnable{
        private boolean direction;

        public TransferThread(boolean direction){
            this.direction = direction;
        }

        @Override
        public void run(){
            for(int i=0; i < 10; i++){
                transfer(direction, (int)(Math.random()*2000));
                try{
                    Thread.sleep((int)(Math.random()*100));
                }catch(InterruptedException ex){
                }
            }
        }
    }
}

しかし、運行の結果の総和は定数20000ではありません.私の夢は原子単位で出荷を移動して加算する操作を実行していないからです.解決策は、ボールを移動するときに同期キーを追加することです.以下のようにします.
public synchronized void transfer(boolean direction, int numToTransfer){

Javaは、生産者/消費者の問題を例に、特殊な待機/通知メカニズムを提供します.
public class ProducerConsumerGame{
    public static void main(String args[]){
        Bucket bucket = new Bucket();
        new Thread(new Producer(bucket)).start();
        new Thread(new Consumer(bucket)).start();
    }
}

final class Consumer implements Runnable{
    private Bucket bucket;

    public Consumer(Bucket bucket){
        this.bucket = bucket;
    }

    @Override
    public void run(){
        for(int i=0; i < 10; i++){
            bucket.get();
        }
    }
}

final class Producer implements Runnable{
    private Bucket bucket;

    public Producer(Bucket bucket){
        this.bucket = bucket;
    }

    @Override
    public void run(){
        for(int i=0; i < 10; i++){
            bucket.put((int)(Math.random()*100));
        }
    }
}

class Bucket{
    private int packOfBalls;
    private boolean available = false;

    public synchronized int get(){
        if(available == false){
            try{
                wait();
            }catch(InterruptedException e){
            }
        }
        System.out.println("Consumer got: "+packOfBalls);
        available = false;
        notify();
        return packOfBalls;
    }

    public synchronized void put(int packOfBalls){
        if(available){
            try{
                wait();
            }catch(InterruptedException e){
            }
        }
        this.packOfBalls = packOfBalls;
        available = true;
        System.out.println("Producer put: "+packOfBalls);
        notify();
    }
}

生産者/消費者モデルは、例えばチャットプログラムなどの現実的な生活シーンで観察することができる.
同期化のタイミング
マルチスレッドでは、通常、複数のスレッドが共有するデータを操作するので、同期は欠かせません.synchronizedの意味は、任意の所与の時間内に、保護されたセグメントにアクセスできるスレッドが1つしかないことを保証する.しかし、これはパフォーマンスの問題をもたらすことが多い.したがって、マルチスレッド・プログラムは、共有されたデータを保護するために十分な同期を必要とし、破壊を避ける必要がありますが、過度な同期を行わないで、volatileキーワードを使用して同期を実現することを考慮することができます.