日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

并发编程问题

發(fā)布時(shí)間:2024/3/24 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并发编程问题 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

并發(fā)編程的目的是為了讓程序運(yùn)行得更快,但是,并不是啟動(dòng)更多的線程就能讓程序最大限度地并發(fā)執(zhí)行。在進(jìn)行并發(fā)編程時(shí),如果希望通過多線程執(zhí)行任務(wù)讓程序運(yùn)行得更快,會(huì)面臨非常多的挑戰(zhàn),比如上下文切換的問題、死鎖的問題,以及受限于硬件和軟件的資源限制 問題,本章會(huì)介紹幾種并發(fā)編程的挑戰(zhàn)以及解決方案。

上下文切換

CPU通過時(shí)間片分配算法來循環(huán)執(zhí)行任務(wù),當(dāng)前任務(wù)執(zhí)行一個(gè)時(shí)間片后會(huì)切換到下一個(gè) 任務(wù)。但是,在切換前會(huì)保存上一個(gè)任務(wù)的狀態(tài),以便下次切換回這個(gè)任務(wù)時(shí),可以再加載這個(gè)任務(wù)的狀態(tài)。所以任務(wù)從保存到再加載的過程就是一次上下文切換。

多線程一定快嗎

當(dāng)并發(fā)執(zhí)行累加操作不超過百萬次時(shí),速度會(huì)比串行執(zhí)行累加操作要慢。那么,為什么并發(fā)執(zhí)行的速度會(huì)比串行慢呢?這是因?yàn)榫€程有創(chuàng)建和上下文切換的開銷。

測(cè)試上下文切換次數(shù)和時(shí)長

下面我們來看看有什么工具可以度量上下文切換帶來的消耗。

使用Lmbench3是一個(gè)性能分析工具,可以測(cè)量上下文切換的時(shí)長。
使用vmstat可以測(cè)量上下文切換的次數(shù)。

如何減少上下文切換

減少上下文切換的方法有無鎖并發(fā)編程、CAS算法、使用最少線程和使用協(xié)程。

無鎖并發(fā)編程。多線程競(jìng)爭鎖時(shí),會(huì)引起上下文切換,所以多線程處理數(shù)據(jù)時(shí),可以用一些辦法來避免使用鎖,如將數(shù)據(jù)的ID按照Hash算法取模分段,不同的線程處理不同段的數(shù)據(jù)。
CAS算法。Java的Atomic包使用CAS算法來更新數(shù)據(jù),而不需要加鎖。
使用最少線程。避免創(chuàng)建不需要的線程,比如任務(wù)很少,但是創(chuàng)建了很多線程來處理,這 樣會(huì)造成大量線程都處于等待狀態(tài)。
協(xié)程:在單線程里實(shí)現(xiàn)多任務(wù)的調(diào)度,并在單線程里維持多個(gè)任務(wù)間的切換。

減少上下文切換

查看線程狀態(tài),看是否有機(jī)會(huì)來減少上下文切換次數(shù)。
第一步:用jstack命令dump線程信息,看看某一進(jìn)程里的線程都在做什么。

jstack pid > /home/develop/dump

第二步:統(tǒng)計(jì)所有線程分別處于什么狀態(tài)。

grep java.lang.Thread.State dump17 | awk ‘{print $2$3$4$5}’ | sort |uniq -c

如果處于空閑的線程過多,可以合理降低線程數(shù)量。因?yàn)槊恳淮螐?WAITTING到RUNNABLE都會(huì)進(jìn)行一次上下文的切換。讀者也可以使用vmstat命令測(cè)試一下。

死鎖

產(chǎn)生條件

互斥條件:進(jìn)程要求對(duì)所分配的資源進(jìn)行排它性控制,即在一段時(shí)間內(nèi)某資源僅為一進(jìn)程所占用。
請(qǐng)求和保持條件:當(dāng)進(jìn)程因請(qǐng)求資源而阻塞時(shí),對(duì)已獲得的資源保持不放。
不剝奪條件:進(jìn)程已獲得的資源在未使用完之前,不能剝奪,只能在使用完時(shí)由自己釋放。
環(huán)路等待條件:在發(fā)生死鎖時(shí),必然存在一個(gè)進(jìn)程–資源的環(huán)形鏈。

避免死鎖的幾個(gè)常見方法。

避免一個(gè)線程同時(shí)獲取多個(gè)鎖。
避免一個(gè)線程在鎖內(nèi)同時(shí)占用多個(gè)資源,盡量保證每個(gè)鎖只占用一個(gè)資源。
嘗試使用定時(shí)鎖,使用lock.tryLock(timeout)來替代使用內(nèi)部鎖機(jī)制。
對(duì)于數(shù)據(jù)庫鎖,加鎖和解鎖必須在一個(gè)數(shù)據(jù)庫連接里,否則會(huì)出現(xiàn)解鎖失敗的情況。

資源限制的挑戰(zhàn)

什么是資源限制

資源限制是指在進(jìn)行并發(fā)編程時(shí),程序的執(zhí)行速度受限于計(jì)算機(jī)硬件資源或軟件資源。

資源限制引發(fā)的問題

在并發(fā)編程中,將代碼執(zhí)行速度加快的原則是將代碼中串行執(zhí)行的部分變成并發(fā)執(zhí)行,
但是如果將某段串行的代碼并發(fā)執(zhí)行,因?yàn)槭芟抻谫Y源,仍然在串行執(zhí)行,這時(shí)候程序不僅不
會(huì)加快執(zhí)行,反而會(huì)更慢,因?yàn)樵黾恿松舷挛那袚Q和資源調(diào)度的時(shí)間。

如何解決資源限制的問題

對(duì)于硬件資源限制,可以考慮使用集群并行執(zhí)行程序。既然單機(jī)的資源有限制,那么就讓
程序在多機(jī)上運(yùn)行。比如使用ODPS、Hadoop或者自己搭建服務(wù)器集群,不同的機(jī)器處理不同
的數(shù)據(jù)。可以通過“數(shù)據(jù)ID%機(jī)器數(shù)”,計(jì)算得到一個(gè)機(jī)器編號(hào),然后由對(duì)應(yīng)編號(hào)的機(jī)器處理這 筆數(shù)據(jù)。
對(duì)于軟件資源限制,可以考慮使用資源池將資源復(fù)用。比如使用連接池將數(shù)據(jù)庫和Socket
連接復(fù)用,或者在調(diào)用對(duì)方webservice接口獲取數(shù)據(jù)時(shí),只建立一個(gè)連接。

在資源限制情況下進(jìn)行并發(fā)編程

如何在資源限制的情況下,讓程序執(zhí)行得更快呢?方法就是,根據(jù)不同的資源限制調(diào)整
程序的并發(fā)度,比如下載文件程序依賴于兩個(gè)資源——帶寬和硬盤讀寫速度。有數(shù)據(jù)庫操作
時(shí),涉及數(shù)據(jù)庫連接數(shù),如果SQL語句執(zhí)行非常快,而線程的數(shù)量比數(shù)據(jù)庫連接數(shù)大很多,則某些線程會(huì)被阻塞,等待數(shù)據(jù)庫連接。

小結(jié)
java提供的juc工具類已經(jīng)可以充分解決以上出現(xiàn)的幾個(gè)問題。

本章知識(shí)點(diǎn)如下:

什么是下文切換
多線程一定快嗎
如何測(cè)試上下文切換次數(shù)和時(shí)長
如何減少上下文切換
死鎖如何產(chǎn)生
如何避免死鎖
什么是資源限制
如何解決資源限制的問題

附源碼1單線程與多線程性能對(duì)比:

public class ConcurrencyTest {private static final long count = 10000l;public static void main(String[] args) throws InterruptedException {concurrency();serial();}private static void concurrency() throws InterruptedException {long start = System.currentTimeMillis();Thread thread = new Thread(new Runnable() {@Overridepublic void run() {int a = 0;for (long i = 0; i < count; i++) {a += 5;}}});thread.start();int b = 0;for (long i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;thread.join();System.out.println("concurrency :" + time + "ms,b=" + b);}private static void serial() {long start = System.currentTimeMillis();int a = 0;for (long i = 0; i < count; i++) {a += 5;}int b = 0;for (long i = 0; i < count; i++) {b--;}long time = System.currentTimeMillis() - start;System.out.println("serial:" + time + "ms,b=" + b + ",a=" + a);} }

附源碼2 死鎖:

public class DeadLockDemo {private static String A = "A";private static String B = "B";public static void main(String[] args) {new DeadLockDemo().deadLock();}private void deadLock() {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (A) {try {Thread.currentThread().sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (B) {System.out.println("1");}}}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {synchronized (B) {synchronized (A) {System.out.println("2");}}}});t1.start();t2.start();} }

總結(jié)

以上是生活随笔為你收集整理的并发编程问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。