Java併發面試,幸虧有點道行,不然又被忽悠了

前言

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

要了解這些圖嗎?

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

Java 併發代碼

 
  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的。

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

如果程序順序調用,count的值應該是5000。

 
  1. for(int i=0;i<5000;i++){

  2. add();

  3. }

但是線程池啓動多線程,是併發執行的。每個線程啓動之後,不管是否運行結束,下一個線程會馬上啓動。

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

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

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

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

答案,聲明原子變量 AtomicInteger count

 
  1. public class CountExample2 {

  2.  

  3. // 請求總數

  4. public static int clientTotal = 5000;

  5.  

  6. // 同時併發執行的線程數

  7. public static int threadTotal = 200;

  8.  

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

  10.  

  11. public static void main(String[] args) throws Exception {

  12. ExecutorService executorService = Executors.newCachedThreadPool();

  13. final Semaphore semaphore = new Semaphore(threadTotal);

  14. final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);

  15. for (int i = 0; i < clientTotal ; i++) {

  16. executorService.execute(() -> {

  17. try {

  18. semaphore.acquire();

  19. add();

  20. semaphore.release();

  21. } catch (Exception e) {

  22. log.error("exception", e);

  23. }

  24. countDownLatch.countDown();

  25. });

  26. }

  27. countDownLatch.await();

  28. executorService.shutdown();

  29. log.info("count:{}", count.get());

  30. }

  31. private static void add() {

  32. count.incrementAndGet();

  33. // count.getAndIncrement();

  34. }

  35. }

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

內存模型,也說點簡單的


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


  1. 函數運行時,new的空間,都是放在堆中的。

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


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