JavaマルチスレッドJUC

24205 ワード

1.volatileキーワード
マルチスレッドアクセスの場合、メモリが表示されないという深刻な問題がありますが、メモリアクセスの場合、各スレッドには独自のバッファがあり、変更を行うたびにプライマリからデータにアクセスし、自分のバッファに入れ、変更をした後にプライマリに戻します.これにより、各スレッド間の変数は表示されません.読み出したデータは常にエラーである可能性があるため、この共有変数を透明と呼ぶキーワードがあります.すべての操作がメモリで直接操作されているように、彼はホストのデータを同期し続けているからです.
2.原子性
i++という演算は,実際には下位層では一時変数の方式を用いているが,これでは式であるが,マルチスレッドの場合にセキュリティの問題が発生する.
package atomic;

/**
 * @Author: lwen
 * @Date: Created in 2017/8/19 15:26
 * @Description:
 */

class Test implements Runnable{
    private volatile int i=0;
    @Override
    public void run() {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(i++);
    }
}
public class Main {
    public static void main(String[] args) {
        Test t=new Test();
        for (int i = 0; i < 10; i++) {
            new Thread(t).start();
        }
    }
}

最後に実行した結果、明らかにvolatileというキーワードで、彼は変数の授業をすべてホストメモリで操作させただけだが、彼は反発する役割がなく、簡単にはロックがなく、彼らはタイムリーにホストメモリからデータを手に入れたが、彼らは最新のデータを手に入れ、演算中に結果を提出した人がいたので、重複要素を招いた.最も根本的な原因はi++が3ステップの操作があって、読んで、演算して、書きます
> 1 3 2 0 4 7 6 5 8 8 Process finished with exit code 0
JAvaの下層には、AtomicIntegerなどの原子的な変数が提供されています.彼らは源を発している以上、まず見えます.これらの下位層は主にCAS(CompareAndSet)アルゴリズムを用い,CASアルゴリズムは主にオペレーティングシステムがハードウェア上で提供するサポートである.このアルゴリズムには3つの重要なパラメータがある.1つ目は、Vが演算前にメモリから読み出した値Aを書き込む前にメモリから読み出した値Bが最終的に書き込む必要がある値である.書き込み前に一度判断し、V==Aの場合にのみBを書き込みます.そうしないと、何もしません.
3.CloncurentHahsMap安全なHashMap
これはスレッドの安全なHashMapで、スレッドの安全なHahsMapは自然にHashTableがあると言っていますが、この効率は非常に低いです.主に彼のブラックアウトの粒度が大きすぎて、彼がロックしているのはHashTable全体、つまり2つの関係のないHashTableも互いに反発してアクセスしているからです.jdk 1.5以降に使用されるのがConcurrentHahsMapというもので、その際に主に使用されるロックセグメントメカニズム、つまり元のベースでHashTableを16セグメントに分割し、各セグメントに1つのHashMapを対応させるという2つの相互に関係のないHashMapが同期してアクセスできるようになります.
4.CountDownLatchロック
いわゆるロックとは、スレッドが商談のすべてのスレッドのコードが実行されるまで待ってから実行を開始することであり、彼の下位実装は変数を維持することであり、この変数は現在生存しているスレッドの数であり、彼が0に減少した場合、つまり他のスレッドが実行され終わった場合、このロックスレッドは開始することができる.たとえば、10個のスレッドを開いて何かをし、メインスレッドで10個のスレッドの合計実行時間を統計します.
package latch;

import com.sun.javafx.sg.prism.web.NGWebView;

import java.util.concurrent.CountDownLatch;

/**
 * @Author: lwen
 * @Date: Created in 2017/8/19 16:06
 * @Description:
 */
class Latch implements Runnable{
    private CountDownLatch latch;

    public Latch(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread());
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        latch.countDown();  //      ,          
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        int start= (int) System.currentTimeMillis();
        CountDownLatch downLatch= new CountDownLatch(10);  //      
        Latch latch=new Latch(downLatch);
        for (int i = 0; i < 10; i++) {
            new Thread(latch).start();
        }
        downLatch.await();  //            ,       
        int end= (int) System.currentTimeMillis();
        System.out.println(end-start);
    }
}

4.スレッドの3つ目の作成方法
一般的にスレッドを作成するには、Threadクラスを継承したり、Runnableインタフェースを実装したりしますが、主にRunnableインタフェースを実装することを使用していますが、この2つの方法で値を返さないものを唆していることに注意してください.つまり私はマルチスレッドができないので、いくつかの結果を返すことができません.ここでスレッドを作成する第3の方法、すなわち戻り値を得ることができる方法は、Callableインタフェースを使用することであり、このインタフェースの使用にはFutureTaskクラスが必要であり、このクラスはRunnableとFutureインタフェースを実現し、彼の具体的な使用方法はRunnableインタフェースとは少し異なる.
package future;

import org.omg.PortableInterceptor.INACTIVE;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @Author: lwen
 * @Date: Created in 2017/8/19 16:23
 * @Description:
 */
class Future implements Callable{

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 0; i < 1000; i++) {
            sum+=i;
        }
        return sum;
    }
}

public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Future future=new Future();
        FutureTask task=new FutureTask(future);
        new Thread(task).start();

        System.out.println(task.get());;//        ,                     ,            ,          
    }
}

5.高度な同期
同期問題を解決するには、同期コードブロック、同期関数、同期ロックの3つの方法があります.つまり手動でロックを宣言し、unlockを使用してロックを解除します.
package lock;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author: lwen
 * @Date: Created in 2017/8/19 16:33
 * @Description:
 */

class Ticket implements Runnable{
    private int ticket=100;
    Lock lock=new ReentrantLock();
    @Override
    public void run() {
        while (true) {
            lock.lock();
            try {
                if (ticket != 0) {
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + ":" + ticket);

                }
            }finally {
                lock.unlock();  //      finally         
            }
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Ticket t=new Ticket();
        new Thread(t,"   ").start();
        new Thread(t,"   ").start();
        new Thread(t,"   ").start();
    }
}

6.生産者と消費者のスレッド同期問題
package product;

import java.util.logging.Level;

/**
 * @Author: lwen
 * @Date: Created in 2017/8/19 16:57
 * @Description:
 */
class Clerk {
    private int production=0;

    public synchronized void get() throws InterruptedException {
        while (production>=1){  //notifyAll           ,        while         if
            System.out.println("  ");
            this.wait();
        }
        System.out.println(Thread.currentThread().getName()+":"+ ++production);
        this.notifyAll();

    }

    public synchronized void sale() throws InterruptedException {
        while (production<=0){
            System.out.println("  ");
            this.wait();
        }
        System.out.println(Thread.currentThread().getName()+":"+ --production);
        this.notifyAll();

    }
}


class Product implements Runnable{
    private Clerk clerk;

    public Product(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                clerk.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable{
    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                clerk.sale();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class Main {
    public static void main(String[] args) {
        Clerk clerk=new Clerk();
        Product p=new Product(clerk);
        Consumer consumer=new Consumer(clerk);
        new Thread(p,"   1").start();
        new Thread(p,"   2").start();
        new Thread(consumer,"   1").start();
        new Thread(consumer,"   2").start();
    }
}

7.読み書きロック
書写と読み書きの同時進行を排斥する
package readandwrite;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author: lwen
 * @Date: Created in 2017/8/19 17:29
 * @Description:
 */

class ReadWriteLockDemo {
    private int number=0;
    private ReadWriteLock lock=new ReentrantReadWriteLock();

    public void read(){
        lock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName()+":"+number);
        }finally {
            lock.readLock().unlock();
        }
    }

    public void write(int number) throws InterruptedException {
        lock.writeLock().lock();
        Thread.sleep(20);
        try {
            this.number=number;
            System.out.println("write");
        }finally {
            lock.writeLock().unlock();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        ReadWriteLockDemo readWriteLockDemo=new ReadWriteLockDemo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    readWriteLockDemo.write(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();

        for (int i = 0; i < 20; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    readWriteLockDemo.read();
                }
            }).start();
        }
    }
}

4.スレッドプール
package pool;

import java.util.concurrent.*;

/**
 * @Author: lwen
 * @Date: Created in 2017/8/19 17:56
 * @Description:
 */

class Test implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}


class Test1 implements Callable{

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 0; i <= 100; i++) {
            sum+=i;
        }
        return sum;
    }
}
public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //             ,                     ,                  ,  pid  
        //           ,          
        ExecutorService executor= Executors.newFixedThreadPool(10);  //        
        ExecutorService executor1=Executors.newSingleThreadExecutor(); //        
        ExecutorService executor2=Executors.newCachedThreadPool(); //        
        for (int i = 0; i < 20; i++) {
            executor.submit(new Test());
        }

        Future future=executor1.submit(new Test1());
        System.out.println(future.get());

        executor.shutdown(); //                   
        executor1.shutdown();
        executor2.shutdown();
    }
}

8.スレッドスケジュール:
スレッドスケジューリングは、どのくらい後にどのような操作を実行するかを決定します.
package schedule;

import java.util.Random;
import java.util.concurrent.*;

/**
 * @Author: lwen
 * @Date: Created in 2017/8/19 18:11
 * @Description:
 */


public class Main {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ScheduledExecutorService service= Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 5; i++) {
            Future future=service.schedule(new Callable() {
                @Override
                public Integer call() throws Exception {
                    int random=new Random().nextInt(100);
                    System.out.println(Thread.currentThread().getName()+":"+random);
                    return random;
                }
            },1, TimeUnit.SECONDS);
            System.out.println(future.get());
        }
        service.shutdown();
    }
}