在某些情況下,程序必須等待某個外部操作執行完成,例如輸入操作或輸出操作等,而在等待時程序無法執行其它任何工作.因此,如果在等待的同時可以運行另一個程序,那么無疑提高了資源的利用率.
不同的用戶和程序對計算機資源有著同等的使用權.一種高效的運行方式是通過粗粒度的時間片使這些用戶和程序能共享計算機資源,而不是一個程序從頭運行到尾,然后在啟動下一個程序.
通常來說,在計算機多任務時,應該編寫多個程序,每個程序執行一個任務并在必要時相互通信,這比只編寫一個程序來計算所有的任務更容易實現.
線程安全性可能是非常復雜的,在沒有充足的同步情況下,多線程中的執行操作順序是不可測試,會產生奇怪的問題.
如下代碼實例 : UnsafeSequence.java ,1000個線程,并發10次,value++
public class UnsafeSequence { /** 默認值0 */ private static int value = 0; /** 線程執行數量 */ private static int threadCount = 1000; /** 并發數量 */ private static int concurrentCount = 10; /** 線程池 */ private static ExecutorService executor = Executors.newFixedThreadPool(threadCount); /** 信號量(并發數) */ private static Semaphore semaphore = new Semaphore(concurrentCount); /** 和join方法類似 */ private static CountDownLatch countDownLatch = new CountDownLatch(threadCount); public static int getNext () { return value++; } public static void main (String[] args) { // 啟動100 個線程 并發10次 去累加 value for (int i = 0; i < threadCount; i++) { executor.execute(() -> { try { // 獲取一個許可證 semaphore.acquire(); getNext(); // 計數器減1 countDownLatch.countDown(); // 歸還一個許可證 semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } }); } // 關閉線程池 executor.shutdown(); try { // 阻塞主線程 直到計數器為0 countDownLatch.await(); System.out.println(value); } catch (InterruptedException e) { e.printStackTrace(); } } }
結果可能是1000或者小于1000,問題在于,如果執行的時機不對,那么兩個線程在調用getNext時會得到相同的值,雖然遞增運算看起來是單個操作,但是實際上是三個獨立的操作,讀取value,將value加1,將計算結果寫入value,由于多線程交替運行,因此兩個線程同時執行讀操作,讀到了相同的值,結果寫入主內存,結果就是不同的線程寫入了相同的值.
一個并發應用程序能及時執行的能力稱為活躍性,常見的有死鎖,饑餓,活鎖問題.
性能問題包括多個方面,例如服務器時間過長,響應不夠靈敏,吞吐率過低,資源消耗過高,或者伸縮性較低等.
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。