Javaのマルチスレッド= - 並行性と高いスレッドセーフな、揮発性、アトミッククラス

まず、マルチスレッド

並列並行

パラレル:2つのイベントが同時に、彼らが行われている
、同時に2つのイベントを、場所を取っていると、時間の期間内に(別の実行)

プロセスとスレッド

プロセス:プログラムがメモリで実行され、我々は、プロセスを呼び出す
(プロセス実行部関数を使用して)プロセスを完了するために小さい機能モジュール:スレッド

スレッドは、プロセスの一部であり、
      各プロセスは、独自のメモリ空間(ヒープの別個のスタック独立、等)を有し、少なくとも1つのスレッド
      の各スレッドが別々のスタックを使用してアプリケーションを処理する、ヒープは、プロセスを共有しました 

CPUスレッドコールすばやく別の異なるプロセス・スレッドを切り替える手段
    
分類スレッドスケジューリング:
    時分割スケジュール:各スレッドは、CPUの平均実行有する
    プリエンプティブコールを:ランダムCPUの各スレッドの実行に割り当てられた(特定のスレッドの優先度に関連する数と分布)
    プリエンプティブスケジューリングを使用してすべてのスレッドで私たちのJavaプログラム(Javaプロセス) 

スレッドの状態

NEW(新)、RUNNABLEがブロックされ、(ランニング)(ブロッキング)、WAITING(待機)、TIMED_WAITING(待ち時間)、TERMINATED(終了);次の状態遷移:Threadオブジェクト6つの状態があります。

 

1.Threadクラス

a.Thread类是什么?
    Thread是Java定义好的,代表线程的类,只要创建该类的一个对象,其实就是创建了一个线程
   
b.Thread类的构造方法
    public Thread(); // 无参构造,线程会有默认的名字,Thread-0,Thread-1等...
	public Thread(String name); //带有线程名字的构造

	public Thread(Runnable r);//带有线程任务的构造
	public Thread(Runnable r,String name); //即带有线程名字,又带有线程任务的构造
    
c.Thread类的成员方法
    public String getName(); //获取线程的名字
	public void setName(String name);//修改线程的名字

	public void run();//代表线程要执行的任务,任务有关的代码需要写在次方法中
	public void start();//线程只创建并不会执行,必须调用start开启后才会执行任务

	public static void sleep(long millis); //让当前线程"休眠/暂停"多少毫秒
			这里的当前线程只指 Thread.sleep(1000)这句代码写哪个线程中,哪个线程就是当前线程
	public static Thread currentThread();//获取当前线程对象
			这里的当前线程是指 Thread.currentThread() 这句代码写哪个线程中,哪个线程就是当前线程


线程执行有优先级,优先级越高先执行机会越大(并不是一定先执行!!)。优先级用int的priority参数表示。
线程优先级最高为10,最低为1。默认为5 

継承 - 新しいスレッドの道を作成します。2.

a.描述:
	将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。接下来可以分配并启动该子类的实例
b.分析创建的步骤:
	i.创建子类 继承 Thread
    ii.子类中重写run方法(在run中编写线程要执行的任务代码)
    iii.创建子类对象(实际上就是创建一个线程对象)
    iv. 调用线程对象的start方法(启动该线程)    
c.案例:
	//i.创建子类 继承 Thread
    public class MyThread extends Thread {
        //ii.子类中重写run方法(在run中编写线程要执行的任务代码)
        @Override
        public void run() {
            for (int i = 0; i < 50; i++) {
                System.out.println("子线程..."+i);
            }
        }
    }
	public class ThreadDemo02 {
    public static void main(String[] args) {
        // iii.创建子类对象(实际上就是创建一个线程对象)
        MyThread mt = new MyThread();
        //iv. 调用线程对象的start方法(启动该线程)
        mt.start();
        //主线程 不会等待子线程任务结束
        for (int i = 0; i < 50; i++) {
            System.out.println("主线程..."+i);
        }
    }
}

注意:
	a.我们可以给线程起名字,也可以使用默认的名字
    b.我们获取线程的名字时:
			建议使用通用方式: Thread.currentThread().getName();
			如果是子线程内部也可以直接调用getName()获取子线程的名字

新しいスレッドの実装を作成する2番目の方法_

a.描述
    声明实现 Runnable 接口的类。该类然后实现 run 方法。
    然后可以分配该类的实例,在创建 Thread 时作为一个参数来传递	并启动.
b.分析步骤:
	i.创建实现类 实现 Runnable接口(实际上接口中一个任务方法,run方法)
    ii.实现类重写run方法(run中编写具体的任务代码)
    iii.创建实现类对象(该实现类对象并不是线程对象,我们称为任务对象) 
    iv. 创建Thread对象,同时传入实现类对象
        public Thread(Runnable r);//带有线程任务的构造
	v. 启动该线程(调用线程对象的start方法)
c.代码实现
    //i.创建实现类 实现 Runnable接口(实际上接口中一个任务方法,run方法)
    public class MyRunnable implements Runnable {
        //ii.实现类重写run方法(run中编写具体的任务代码)
        @Override
        public void run() {
            //run中写任务代码
            for (int i = 0; i < 50; i++) {
                System.out.println("子线程..."+i);
            }
        }
    }
    
	public class TestThread {
        public static void main(String[] args) {
            //iii.创建实现类对象(该实现类对象并不是线程对象,我们称为任务对象)
            MyRunnable mr = new MyRunnable();
            //iv. 创建Thread对象,同时传入实现类对象
            Thread tt = new Thread(mr);
            //v. 启动该线程(调用线程对象的start方法)
            tt.start();

            //主线程不会等待子线程执行完毕
            for (int i = 0; i < 50; i++) {
                System.out.println("主线程..."+i);
            }
        }
    }

2つの方法の長所と短所を比較

スレッドの道を作成する2つの方法、達成するためのより良い方法
    スレッドおよびタスクの実装は、独自の組み合わせプログラマによって、分離されているので。インプリメンテーションは、優れている
    B。Javaの単一継承の実装の不足を回避するために
    Cを。スレッドおよびタスクの実装デカップリング、相続スレッドとタスクが結合されている
    スレッドプールのdは、我々は、スレッドのサブクラスを必要とせずに、Runnableを実装クラスを必要としています。
合計する:開発中で、私たちは実装を使用することをお勧めします(間違った道を受け継いと言うことではありません)   

匿名内部クラスは、スレッドを作成する方法を簡素化

匿名内部类作用:
	可以快速创建一个类的子类对象或者一个接口的实现类对象
public class TestDemo {
    public static void main(String[] args) {
        //1.继承方式创建线程
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 50; i++) {
                    System.out.println(Thread.currentThread().getName()+"..."+i);
                }
            }
        }.start();
        //2.实现方式创建线程
        new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i = 0; i < 50; i++) {
                    System.out.println(Thread.currentThread().getName()+"..."+i);
                }
            }
        }).start();
        //主线程不会等待子线程任务结束
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName()+"..."+i);
        }
    }
}        

 

II。高並行性、およびスレッドセーフ

高並行性とスレッドセーフ紹介

高い同時実行は何か:時点を指し、ユーザー(スレッド)の多数が同時に同じリソースにアクセス
スレッドセーフに:時点を指し、「規格外実際の文字の高いデータアクセスが発生した後データは、「スレッド安全性の問題と呼ばれています 

マルチスレッド操作機構

public class MyThread extends Thread { 
    @Override 
    public void run() { 
        for (int i = 0; i < 100; i++) { 
            System.out.println("i = " + i); 
        } 
    } 
}

public class Demo { 
    public static void main(String[] args) { 
        //1.创建两个线程对象 
        MyThread t1 = new MyThread(); 
        MyThread t2 = new MyThread(); 
        //2.启动两个线程 
        t1.start(); 
        t2.start(); 
	} 
}

マルチスレッドのセキュリティ問題 - 可視性

什么有可见性:
	当一个共性变量,被多个线程使用时,其中某个线程对共性变量进行了修改,对于其他线程来说并不是立刻可见的
        其他线程获取的值还是以前的副本(旧的值)
案例:
	public class MyThread extends Thread {
        //无论创建多个MyThread对象,他们共性一个静态变量a
        public static int a = 0;
        @Override
        public void run() {
            System.out.println("线程启动,休息2秒...");
            try { Thread.sleep(1000 * 2); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("将a的值改为1");
            a = 1;
            System.out.println("线程结束...");
        }
    }

	public class TestSafaDemo01 {
        public static void main(String[] args) {
            //1.启动线程
            MyThread t = new MyThread();
            t.start();
            //2.主线程继续
            while (true) {
                if (MyThread.a == 1) {
                    System.out.println("主线程读到了a = 1");
                }
            }
        }
    }

マルチスレッドのセキュリティ問題 - 秩序

秩序は何か:
    コード「再配置」のエクステントは、コードの結果に影響を与えない
    マルチスレッド、「再配置」の場合には、同じコード、結論異なる結果の操作になる可能性がある場合
    、我々がしたいですマルチスレッドではなく、コード「再配置」の場合にはコードが順序付けされることを保証することを確実にする(再配列を使用しないでください!) 

マルチスレッドのセキュリティ問題 - アトミック

どのような原子性:
    ++は++ 1によって2つの段階、最初の値に分け、その後、一般的な変数の割り当てに取り出したときに、共通の変数をスレッド
    値プラス1が取り出された場合、時間の割り当てを持っていなかった、他のスレッドが奪われてCPUは、我々は何のアトミック操作を持たないこのケースを呼び出す++ 

III。volatileキーワード

揮発性がメンバ変数(静的変数)を変更するために使用するキーワードである、彼は変数が可視性と秩序を持っている修正しました

揮発性の解決の可視性

public class MyThread extends Thread {
    //无论创建多个MyThread对象,他们共性一个静态变量a
    public volatile static int a = 0;
    @Override
    public void run() {
        System.out.println("线程启动...");
        try { Thread.sleep(1000 * 2); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("将a的值改为1");
        a = 1;
        System.out.println("线程结束...");
    }
}

public class TestSafaDemo01 {
    public static void main(String[] args) {
        //1.启动线程
        MyThread t = new MyThread();
        t.start();
        //2.主线程继续
        while (true) {
            if (MyThread.a == 1) {
                System.out.println("主线程读到了a = 1");
            }
        }
    }
}

揮発性の解決秩序

揮発性のアトミック性を解決しません

volatile不能解决原子性问题
public class MyThread extends Thread {
    public volatile static int a = 0;
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            a++;
        }
        System.out.println("修改完毕!");
    }
}

public class TestSafeDemo {
    public static void main(String[] args) throws InterruptedException {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.start(); //线程1 对a加了10000次
        t2.start(); // 线程2 对a加了 10000次
        Thread.sleep(1000);
        System.out.println("获取a最终值:" + MyThread.a);
        //总是不准确的。原因:两个线程访问a 的步骤不具有:原子性
    }
}

揮発性の役割

。、変数の可視性を解決するための変数が変更されると、使用スレッドへのすべての変数は、最新の値になります
。この変数のないB。変数の秩序を解決するために、変数を加えた揮発一度、コンパイラが行うコードです再配列
アトミック操作を解決することはできませんC。プロセス変数、変数の操作は、依然として他のスレッドによって中断されていてもよいです  

IV。 - アトム

。?原子タイプAとは何である
    一般的なタイプです:クラスは、操作部材原子の操作作り、(例えばint型、整数、ダブル、ダブルなど)の原子をカプセル化します
?。アトミックアクションクラスBの
    操作に基づく原子を増加または減少し、アトミックであることが保証、他のスレッドが「中断」の中ではないことを保証
するものアトミッククラスC。?
    たとえば:
        int型の変数操作するためのAtomicInteger原子クラス
        原子クラスAtomicLongは、オペレーティングlong変数である
        ブール変数操作のAtomicBooleanを「アトミッククラス」;
注:アトミッククラスは、アトミック性を解決することができるだけでなく、あなたが注文し、視認性を解決することができます

java.util.concurrent.atomic 定義次のパケット 可変 操作 アトミッククラス 」:
1).java.util.concurrent.atomic.AtomicInteger ための: int型 の変数の操作 原子タイプ 」。
2).java.util.concurrent.atomic.AtomicLong :のため に長い の変数操作 原子タイプ 」;
3).java.util.concurrent.atomic.AtomicBoolean :用 ブール の変数操作 原子タイプ 」;

AtomicIntegerクラス

a.AtomicInteger是什么?
    是对int类型变量进行操作的原子类
b.AtomicInteger的构造方法
    public AtomicInteger(int num);
c.AtomicInteger的成员方法
    public int getAndIncrement();//就相当于 变量++  
	public int incrementAndGet();//就相当于 ++变量 
    
d.使用AtomicInteger改写案例    
    public class MyThread extends Thread {
        public static AtomicInteger a = new AtomicInteger(0);
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                a.getAndIncrement();//相当于 a++  先获取在自增1
            }
            System.out.println("修改完毕!");
        }
    }

	public class TestSafeDemo {
        public static void main(String[] args) throws InterruptedException {
            MyThread t1 = new MyThread();
            MyThread t2 = new MyThread();

            t1.start(); //线程1 对a加了10000次
            t2.start(); // 线程2 对a加了 10000次
            Thread.sleep(1000);
            System.out.println("获取a最终值:" + MyThread.a);
            //总是不准确的。原因:两个线程访问a 的步骤不具有:原子性
        }
    }

安全でない クラス、コール: compareAndSwapInt() メソッドは、この方法のいくつかのパラメータ:
VAR1は :着信 のAtomicIntegerは、 オブジェクト
VAR2 AtommicInteger 内部変数のオフセットアドレス
VAR5 :前に撤退 のAtomicIntegerの 値。
+ VAR4のVAR5 :予想される結果
この方法は、使用しています コンペア・アンド・スワップ (比較とスワップ)」 使用するメカニズム にvar1 var2の 最初の捕捉メモリを
AtomicInteger 値で、その後、渡された、以前に取得したの値 VAR5は 、いくつかの比較を行い、現在のメモリ値の比較と期待値であり、
変更に関する合意場合は、同じである VAR5 + VAR4 、それ以外のサイクルは継続し、再び取得 のAtomicIntegerの 値を、次に比較します
取引所、これまでの交流の成功まで。
 
compareAndSwapInt() メソッドは、 スレッドセーフ されます。
 
私たちは、2つのスレッドが交互に動作していることを前提とし、それがどのように動作するかを参照してください。
初期 のAtomicIntegerの 0
スレッド 実行:VAR5 = this.getIntVolatile(VAR1、VAR2)を、結果が得られた:0
スレッド Aが 中断されます
スレッド Bの 実行: VAR5 = this.getIntVolatile(VAR1、VAR2); 結果が得られた: 0
スレッド B 実行: this.compareAndSwapInt(VAR1、VAR2、VAR5、VAR5 + VAR4)
スレッド Bは 、正常 のAtomicIntegerの 値に変更された 1
スレッド 、回復運転を実行します。this.compareAndSwapInt(VAR1、VAR2、VAR5、VAR5 + VAR4)
このとき、スレッド Aの 使用 VAR1 VAR2 から のAtomicIntegerの 値が得られた: 1を 、着信 VAR5が ある 0 、比較は、復帰に失敗しました
、ループが続きます。
スレッド 実行:VAR5 = this.getIntVolatile(VAR1、VAR2)を、結果が得られた:1
スレッド の実行を:this.compareAndSwapInt(VAR1、VAR2、VAR5、VAR5 + VAR4)
この時点で、スレッド Aの 使用 VAR1 VAR2 から のAtomicIntegerの 取得した値: 1 、着信 VAR5 1 、より成功した、改変がそれらになり
ある VAR5 + VAR4 すなわち、 2 のAtomicIntegerの 値が変更された 2 、端部が。
CASの 楽観的ロック:メカニズムとしても知られています。比較の結果のほとんどがあるので trueに 、直接変更。どこ意志をマルチスレッドのほんの一部
つながる のCAS 再び失敗、およびサイクル。

AtomicIntegerArray类

従来のアレイ型アトミック操作: 1).java.util.concurrent.atomic.AtomicIntegetArray: のために INT -atomicアレイ動作。
2).java.util.concurrent.atomic.AtomicLongArray :のため の長い -atomicアレイ動作。
3).java.utio.concurrent.atomic.AtomicReferenceArray : -配列操作の種類にアトム参照。

クラスの非原子の配列は、マルチスレッドで問題が発生します

public class MyThread extends Thread {
    public static int[] intArray = new int[1000];//不直接使用数组

    @Override
    public void run() {
        for (int i = 0; i < intArray.length; i++) {
            intArray[i]++;
        }
    }
}

public class TestDemo01 {
    public static void main(String[] args) throws InterruptedException {
        //创建1000个线程,每个线程为数组的每个元素+1
        for (int i = 0; i < 1000; i++) {
            new MyThread().start();
        }

        Thread.sleep(1000 * 5);//让所有线程执行完毕
        System.out.println("主线程休息5秒醒来");
        for (int i = 0; i < MyThread.intArray.length; i++) {
            System.out.println(MyThread.intArray[i]);
        }
    }
}
打印结果:
	1000,1000,1000,999,1000,1000,1000,1000,....
有个别元素是小于1000的,因为int[]是非原子类数组,不能保存原子性!!!

クラスの原子配列の使用は、問題を解決するために、原子性を確保するために

public class MyThread extends Thread {
    public static int[] intArray = new int[1000];//不直接使用数组
    public static AtomicIntegerArray arr = new AtomicIntegerArray(intArray);
    @Override
    public void run() {
//        for (int i = 0; i < intArray.length; i++) {
//            intArray[i]++;
//        }
        for (int i = 0; i < arr.length(); i++) {
            arr.addAndGet(i, 1);//将i位置上的元素 + 1,相当于 ++数组[i]
        }

    }
}

public class TestDemo01 {
    public static void main(String[] args) throws InterruptedException {
        //创建1000个线程,每个线程为数组的每个元素+1
        for (int i = 0; i < 1000; i++) {
            new MyThread().start();
        }

        Thread.sleep(1000 * 5);//让所有线程执行完毕
        System.out.println("主线程休息5秒醒来");
//        for (int i = 0; i < MyThread.intArray.length; i++) {
//            System.out.println(MyThread.intArray[i]);
//        }
        for (int i = 0; i < MyThread.arr.length(); i++) {
            System.out.println(MyThread.arr.get(i));
        }
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

公開された103元の記事 ウォン称賛15 ビュー270 000 +

おすすめ

転載: blog.csdn.net/u010581811/article/details/104882590