Java併發面試,幸好有點道行,否則又被忽悠了

前言

面試Java,必然要被問Java內存模型和Java併發開發。我被問到的時候,內心慌得一批,「額,是在《Thinking in Java》裏面寫的嗎?果真天天增刪改太low了」面試

要了解這些圖嗎?

我但願能解釋的再簡單一些,以上都不用

Java 併發代碼shell

複製代碼
  1. public class Example1 {
  2. public static int count = 0;
  3. public static int clientTotal = 5000;
  4. public static void main(String[] args) throws Exception {
  5. ExecutorService executorService = Executors.newCachedThreadPool();
  6. for (int i = 0; i < clientTotal ; i++) {
  7. executorService.execute(() -> {
  8. try {
  9. add();
  10. } catch (Exception e) {
  11. log.error("exception", e);
  12. }
  13. });
  14. }
  15. }
  16. private static void add() {
  17. count++;
  18. }
  19. }

若是上面代碼執行,count的值是多少?(爲了說明重點問題,沒有寫最後打印的代碼) 5000?屢次運行的結果,count的值是小於5000的。bash

解釋一下上面的程序,首先定義了一個線程池,啓動5000個線程執行add()操做,add函數處理靜態成員變量count。多線程

若是程序順序調用,count的值應該是5000。併發

複製代碼
  1. for(int i=0;i<5000;i++){
  2. add();
  3. }

可是線程池啓動多線程,是併發執行的。每一個線程啓動以後,無論是否運行結束,下一個線程會立刻啓動。異步

啓動線程的過程,是一個異步過程,啓動線程當即返回,啓動下一個進程。函數

當多個線程對同一個變量add進行操做的時候,就會發生寫寫衝突。ui

線程一、線程2 同時對值爲0的變量進行操做,結果返回1,而不是2。若是這個地方想不明白,就請留言,或者看看文章頂部那些原理圖。spa

要不簡單點,記住「多線程對全局變量的寫操做會發生衝突」。線程

答案,聲明原子變量 AtomicInteger count

複製代碼
  1. public class CountExample2 {

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

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

  6. public static AtomicInteger count = new AtomicInteger(0);

  7. public static void main(String[] args) throws Exception {
  8. ExecutorService executorService = Executors.newCachedThreadPool();
  9. final Semaphore semaphore = new Semaphore(threadTotal);
  10. final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
  11. for (int i = 0; i < clientTotal ; i++) {
  12. executorService.execute(() -> {
  13. try {
  14. semaphore.acquire();
  15. add();
  16. semaphore.release();
  17. } catch (Exception e) {
  18. log.error("exception", e);
  19. }
  20. countDownLatch.countDown();
  21. });
  22. }
  23. countDownLatch.await();
  24. executorService.shutdown();
  25. log.info("count:{}", count.get());
  26. }
  27. private static void add() {
  28. count.incrementAndGet();
  29. // count.getAndIncrement();
  30. }
  31. }

注,上面的代碼用了生成者消費者模式,5000個生產者,200個消費者,對程序併發作必定限制,防止5000個線程卡死計算機。

內存模型,也說點簡單的

    1. 棧(heap),函數加載的時候,爲函數內部變量分配的空間。和父函數的內部變量和運行指針共享同一塊區域。
    1. 函數運行時,new的空間,都是放在堆中的。

這個就是C的內存模型,作shellcode的基礎知識。

相關文章
相關標籤/搜索