Java併發編程與高併發解決方案(一)

 

Java高併發併發導圖

 

 

 

首先介紹連接池

1:ExecutorService是Executor直接的擴展接口,也是最常用的線程池接口,我們通常見到的線程池定時任務線程池都是它的實現類。

2:Executor的實現提供的一些方法可以返回一個 Future , 通過它我們可以跟蹤到異步任務的執行和停止。

3:ExecutorService(線程池)可以被關閉來拒絕新任務。有兩個不同的方法來關閉。 
shutdown方法 在關閉 ExecutorService 之前等待提交的任務執行完成。 
shutdownNow方法 會阻止開啓新的任務並且嘗試停止當前正在執行的線程,一旦調用該方法,線程池中將沒有激活的任務,沒有等待執行的任務,也沒有新任務提交。 
沒有任務執行的ExecutorService將會被回收。

4:方法submit擴展了Executor.execute(Runnable) 方法, 創建並返回一個 Future 結果,這個Future可以取消任務的執行或者等待完成得到返回值。 
5:方法invokeAny and invokeAll 可以執行一組任務,等待至少一個任務或者多個任務完成(ExecutorCompletionService擴展了這些方法的實現)。

以下是這個接口定義的方法:

void shutdown();
  • 發起一個關閉請求,已提交的任務會執行,但不會接受新的任務請求了。 這個方法不會等待已提交的任務全部執行完成,如果你希望這樣做,可以使用awaitTermination方法

List<Runnable> shutdownNow();
  • 這個方法會停掉所有執行中的任務,取消等待中的任務,返回等待執行的任務 的list,方法不會等待執行中的任務停止,如果你希望這樣做,可以使用awaitTermination方法

boolean isShutdown();
  • 如果線程池停止完成返回true

boolean isTerminated();
  • 如果線程池停止完成返回true ,當所有的任務都停止了,返回true, 注意:只有調用 shutdown 或者 shutdownNow 才返回true

boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
  • 調用此方法,在shutdown請求發起後,除非以下任何一種情況發生,否則當前線程將一直到阻塞。 1、所有任務執行完成 ,2、超過超時時間 ,3、當前線程被中斷

<T> Future<T> submit(Callable<T> task);
  • 提交一個帶有返回值的任務(Callable),返回值爲Future,表示了任務的執行完成結果,Future.get()方法返回成功執行後的結果。 

如果你想要阻塞當前線程知道執行完成返回結果,那麼你可以這樣做: 
result = exec.submit(aCallable).get();


<T> Future<T> submit(Runnable task, T result);
  • 提交一個Runnable任務執行,返回一個Future做爲任務task的代理,Future.get()方法在執行成功後可以返回結果。 Runnable task 提交的任務 ,T results 執行的結果

 Future<?> submit(Runnable task);
  • 提交一個Runnable任務執行,返回一個Future做爲任務task的代理,Future.get()方法在執行成功後可以返回結果。

 <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
  • 執行一組任務,返回一個Future的list,其中的Future持有任務執行完成的結果和狀態 ,對於每一個返回的結果,uture.isDone = true 

完成的任務可能正常結束或者異常結束, 
如果在任務執行過程中參數Collection改變了,那麼返回結果是不確定的。


<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit)
        throws InterruptedException;
  • 執行一組任務,返回一個Future的list,其中的Future持有任務執行完成的結果和狀態 ,如果所有任務執行完成或者超時,對於每一個返回的結果中,Future.isDone = true ,當返回時,未執行完成的任務被取消,完成的任務可能正常結束或者異常結束, 如果在任務執行過程中參數Collection改變了,那麼返回結果是不確定的。

<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
  • 執行一組任務,當成功執行完一個任務(沒有拋異常),就返回結果,不論正常返回還是異常結束,未執行的任務都會被取消。如果在任務執行過程中參數Collection改變了,那麼返回結果是不確定的。

<T> T invokeAny(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
  • 執行一組任務,在未超時情況下,當成功執行完一個任務(沒有拋異常),就返回結果。不論正常返回還是異常結束,未執行的任務都會被取消。 如果在任務執行過程中參數Collection改變了,那麼返回結果是不確定的。

 

Semaphore的使用

1:線程不安全的:由於add方法不是線程安全的


    // 請求總數
    public static int clientTotal = 5000;
    // 同時併發執行的線程數
    public static int threadTotal = 200;
    public static int count = 0;
    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        // 創建信號量
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    // 從信號量中獲取一個允許機會
                    semaphore.acquire();
                    add();
                    // 釋放允許,將佔有的信號量歸還
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);
    }

    private static void add() {
        count++;
    }

2:線程安全的:由於AtomicInteger是線程安全的,AtomicInteger和AtomicLong都是線程安全的

    // 請求總數
    public static int clientTotal = 5000;
    // 同時併發執行的線程數
    public static int threadTotal = 200;
    public static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count.get());
    }

    private static void add() {
        count.incrementAndGet();
        // count.getAndIncrement();
    }

3:線程安全的:由於add方法是線程安全的

    // 請求總數
    public static int clientTotal = 5000;

    // 同時併發執行的線程數
    public static int threadTotal = 200;

    public static int count = 0;

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);
    }

    private synchronized static void add() {
        count++;
    }

4:線程不安全的:由於add方法是線程安全的

volatile關鍵字的作用是,強制變量每次都讀取公共內存,這樣,一旦有線程改變變量的值,其他線程馬上就能發現。這就是定義裏,所有線程可見的含義。 
但是要注意,此關鍵字只能保證變量的可見性,不能保證原子性,也不會阻塞線程。也就是說多個線程併發修改變量時,還是會有併發性問題。要解決併發性的問題,還是隻能用synchronized關鍵字。應用的場景,就是一旦改動,所有線程都能馬上感知到的的情況。例如示例代碼設置子線程停止循環的標誌。

    // 請求總數
    public static int clientTotal = 5000;
    // 同時併發執行的線程數
    public static int threadTotal = 200;
    public static volatile int count = 0;

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);
    }

    private static void add() {
        count++;
        // 1、count
        // 2、+1
        // 3、count
    }

 

1:AtomicInteger實現線程安全

 // 請求總數
    public static int clientTotal = 5000;
    // 同時併發執行的線程數
    public static int threadTotal = 200;
    public static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count.get());
    }

    private static void add() {
        count.incrementAndGet();
        // count.getAndIncrement();
    }

2:AtomicLong實現線程安全

    // 請求總數
    public static int clientTotal = 5000;
    // 同時併發執行的線程數
    public static int threadTotal = 200;
    public static AtomicLong count = new AtomicLong(0);

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count.get());
    }

    private static void add() {
        count.incrementAndGet();
        // count.getAndIncrement();
    }

3:LongAdder實現線程安全

// 請求總數
    public static int clientTotal = 5000;
    // 同時併發執行的線程數
    public static int threadTotal = 200;
    public static LongAdder count = new LongAdder();

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);
    }

    private static void add() {
        count.increment();
    }

 

4:AtomicReference實現線程安全


    private static AtomicReference<Integer> count = new AtomicReference<>(0);

    public static void main(String[] args) {
        count.compareAndSet(0, 2); // 2
        count.compareAndSet(0, 1); // no
        count.compareAndSet(1, 3); // no
        count.compareAndSet(2, 4); // 4
        count.compareAndSet(3, 5); // no
        log.info("count:{}", count.get());
    }

5:AtomicIntegerFieldUpdater實現線程安全

private static AtomicIntegerFieldUpdater<AtomicExample5> updater =
            AtomicIntegerFieldUpdater.newUpdater(AtomicExample5.class, "count");

    @Getter
    public volatile int count = 100;

    public static void main(String[] args) {

        AtomicExample5 example5 = new AtomicExample5();

        if (updater.compareAndSet(example5, 100, 120)) {
            log.info("update success 1, {}", example5.getCount());
        }

        if (updater.compareAndSet(example5, 100, 120)) {
            log.info("update success 2, {}", example5.getCount());
        } else {
            log.info("update failed, {}", example5.getCount());
        }
    }
5:AtomicBoolean實現線程安全
private static AtomicBoolean isHappened = new AtomicBoolean(false);

    // 請求總數
    public static int clientTotal = 5000;

    // 同時併發執行的線程數
    public static int threadTotal = 200;

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    test();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("isHappened:{}", isHappened.get());
    }

    private static void test() {
        if (isHappened.compareAndSet(false, true)) {
            log.info("execute");
        }
    }

 

Synchronized實現線程安全

// 修飾一個代碼塊 作用對象:調用這個方法的對象(如果new多個就是併發執行的了)
public void test1(int j) {
    synchronized (this) {
        for (int i = 0; i < 10; i++) {
            log.info("test1 {} - {}", j, i);
        }
    }
}

// 修飾一個方法  作用對象:調用這個方法的對象(同一個對象要按照順序執行)
public synchronized void test2(int j) {
    for (int i = 0; i < 10; i++) {
        log.info("test2 {} - {}", j, i);
    }
}

如果synchronized 修飾的方法作爲父類,他的子類調用他的synchronized 方法,是不加synchronized 得


// 修飾一個類   無論多少個線程調用都是按照順序的
public static void test1(int j) {
    synchronized (SynchronizedExample2.class) {
        for (int i = 0; i < 10; i++) {
            log.info("test1 {} - {}", j, i);
        }
    }
}

// 修飾一個靜態方法  無論多少個線程調用都是按照順序的
public static synchronized void test2(int j) {
    for (int i = 0; i < 10; i++) {
        log.info("test2 {} - {}", j, i);
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章