本文目錄一覽:
北大青鳥java培訓:Java並發編程常用的類和集合?
AtomicInteger可以用原子方式更新int值。
類AtomicBoolean、AtomicInteger、AtomicLong和AtomicReference的實例各自提供對相應類型單個變量的訪問和更新。
java課程培訓機構認為基本的原理都是使用CAS操作:booleancompareAndSet(expectedValue,updateValue);如果此方法(在不同的類間參數類型也不同)當前保持expectedValue,則以原子方式將變量設置為updateValue,並在成功時報告true。
循環CAS,參考AtomicInteger中的實現:publicfinalintgetAndIncrement(){ for(;;){ intcurrent=get(); intnext=current+1; if(compareAndSet(current,next)) returncurrent; } } publicfinalbooleancompareAndSet(intexpect,intupdate){ returnunsafe.compareAndSwapInt(this,valueOffset,expect,update); }ABA問題因為CAS需要在操作值的時候檢查下值有沒有發生變化,如果沒有發生變化則更新,但是如果一個值原來是A,變成了B,又變成了A,那麼使用CAS進行檢查時會發現它的值沒有發生變化,但是實際上卻變化了。
ABA問題的解決思路就是使用版本號。
在變量前面追加上版本號,每次變量更新的時候把版本號加一,那麼A-B-A就會變成1A-2B-3A。
從Java1.5開始JDK的atomic包里提供了一個類AtomicStampedReference來解決ABA問題。
這個類的compareAndSet方法作用是首先檢查當前引用是否等於預期引用,並且當前標誌是否等於預期標誌,如果全部相等,則以原子方式將該引用和該標誌的值設置為給定的更新值。
ArrayBlockingQueue一個由數組支持的有界阻塞隊列。
此隊列按FIFO(先進先出)原則對元素進行排序。
隊列的頭部是在隊列中存在時間最長的元素。
隊列的尾部是在隊列中存在時間最短的元素。
新元素插入到隊列的尾部,隊列獲取操作則是從隊列頭部開始獲得元素。
這是一個典型的“有界緩存區”,固定大小的數組在其中保持生產者插入的元素和使用者提取的元素。
一旦創建了這樣的緩存區,就不能再增加其容量。
試圖向已滿隊列中放入元素會導致操作受阻塞;試圖從空隊列中提取元素將導致類似阻塞。
此類支持對等待的生產者線程和使用者線程進行排序的可選公平策略。
默認情況下,不保證是這種排序。
然而,通過將公平性(fairness)設置為true而構造的隊列允許按照FIFO順序訪問線程。
公平性通常會降低吞吐量,但也減少了可變性和避免了“不平衡性”。
LinkedBlockingQueue一個基於已鏈接節點的、範圍任意的blockingqueue。
此隊列按FIFO(先進先出)排序元素。
隊列的頭部是在隊列中時間最長的元素。
隊列的尾部是在隊列中時間最短的元素。
新元素插入到隊列的尾部,並且隊列獲取操作會獲得位於隊列頭部的元素。
鏈接隊列的吞吐量通常要高於基於數組的隊列,但是在大多數並發應用程序中,其可預知的性能要低。
可選的容量範圍構造方法參數作為防止隊列過度擴展的一種方法。
如果未指定容量,則它等於Integer.MAX_VALUE。
除非插入節點會使隊列超出容量,否則每次插入後會動態地創建鏈接節點。
如果構造一個LinkedBlockingQueue對象,而沒有指定其容量大小,LinkedBlockingQueue會默認一個類似無限大小的容量(Integer.MAX_VALUE),這樣的話,如果生產者的速度一旦大於消費者的速度,也許還沒有等到隊列滿阻塞產生,系統內存就有可能已被消耗殆盡了。
java並發包有哪些類
1、CyclicBarrier
一個同步輔助類,允許一組線程相互等待,直到這組線程都到達某個公共屏障點。該barrier在釋放等待線程後可以重用,因此稱為循環的barrier。
來個示例:
[java] view plain copy
package test;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Recipes_CyclicBarrier {
public static CyclicBarrier barrier = new CyclicBarrier(10);
public static void main(String[] args){
ExecutorService executor = Executors.newCachedThreadPool();//FixedThreadPool(10);
for(int i=1;i=10;i++){
executor.submit(new Thread(new Runner(i+”號選手”)));
}
executor.shutdown();
}
}
class Runner implements Runnable{
private String name;
public Runner(String name){
this.name = name;
}
@Override
public void run() {
System.out.println(name + “準備好了。”);
try {
Recipes_CyclicBarrier.barrier.await(); //此處就是公共屏障點,所有線程到達之後,會釋放所有等待的線程
} catch (Exception e) {
}
System.out.println(name + “起跑!”);
}
}
2、CountDownLatch
CountDownLatch和CyclicBarrier有點類似,但是還是有些區別的。CountDownLatch也是一個同步輔助類,它允許一個或者多個線程一直等待,直到正在其他線程中執行的操作完成。它是等待正在其他線程中執行的操作,並不是線程之間相互等待。CountDownLatch初始化時需要給定一個計數值,每個線程執行完之後,必須調用countDown()方法使計數值減1,直到計數值為0,此時等待的線程才會釋放。
來個示例:
[java] view plain copy
package test;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchDemo {
public static CountDownLatch countDownLatch = new CountDownLatch(10);//初始化計數值
public static void main(String[] args){
ExecutorService executor = Executors.newCachedThreadPool();//FixedThreadPool(10);
for(int i=1;i=10;i++){
executor.submit(new Thread(new Runner1(i+”號選手”)));
}
executor.shutdown();
}
}
class Runner1 implements Runnable{
private String name;
public Runner1(String name){
this.name = name;
}
@Override
public void run() {
System.out.println(name + “準備好了。”);
CountDownLatchDemo.countDownLatch.countDown(); //計數值減1
try {
CountDownLatchDemo.countDownLatch.await();
} catch (Exception e) {
}
System.out.println(name + “起跑!”);
}
}
3、CopyOnWriteArrayList CopyOnWriteArraySet
CopyOnWriteArrayList CopyOnWriteArraySet是並發容器,適合讀多寫少的場景,如網站的黑白名單設置。缺點是內存佔用大,數據一致性的問題,CopyOnWrite容器只能保證數據最終的一致性,不能保證數據實時一致性。鑒於它的這些缺點,可以使用ConcurrentHashMap容器。
實現原理:新增到容器的數據會放到一個新的容器中,然後將原容器的引用指向新容器,舊容器也會存在,因此會有兩個容器佔用內存。我們也可以用同樣的方式實現自己的CopyOnWriteMap。
4、ConcurrentHashMap
ConcurrentHashMap同樣是一個並發容器,將同步粒度最小化。
實現原理:ConcurrentHashMap默認是由16個Segment組成,每個Segment由多個Hashtable組成,數據變更需要經過兩次哈希算法,第一次哈希定位到Segment,第二次哈希定位到Segment下的Hashtable,容器只會將單個Segment鎖住,然後操作Segment下的Hashtable,多個Segment之間不受影響。如果需要擴容不是對Segment擴容而是對Segment下的Hashtable擴容。雖然經過兩次哈希算法會使效率降低,但是比鎖住整個容器效率要高得多。
5、BlockingQueue
BlockingQueue只是一個接口,它的實現類有ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue、DelayQueue、LinkedBlockingDeque。
ArrayBlockingQueue:由數據支持的有界阻塞隊列。
LinkedBlockingQueue:基於鏈接節點、範圍任意的阻塞隊列。
PriorityBlockingQueue:無界阻塞隊列。
SynchronousQueue:一種阻塞隊列,其中每個插入操作必須等待另一個線程的對應移除操作。
DelayQueue:Delayed元素的一個無界阻塞隊列。
LinkedBlockingDeque:基於鏈接節點、範圍任意的雙端阻塞隊列,可以在隊列的兩端添加、移除元素。
6、Lock
Lock分為公平鎖和非公平鎖,默認是非公平鎖。實現類有ReetrantLock、ReetrantReadWriteLock,都依賴於AbstractQueuedSynchronizer抽象類。ReetrantLock將所有Lock接口的操作都委派到Sync類上,Sync有兩個子類:NonFairSync和FaiSync,通過其命名就能知道分別處理非公平鎖和公平鎖的。AbstractQueuedSynchronizer把所有請求構成一個CLH隊列,這裡是一個虛擬隊列,當有線程競爭鎖時,該線程會首先嘗試是否能獲取鎖,這種做法對於在隊列中等待的線程來說是非公平的,如果有線程正在Running,那麼通過循環的CAS操作將此線程增加到隊尾,直至添加成功。
7、Atomic包
Atomic包下的類實現了原子操作,有對基本類型如int、long、boolean實現原子操作的類:AtomicInteger、AtomicLong、AtomicBoolean,如果需要對一個對象進行原子操作,也有對對象引用進行原子操作的AtomicReference類,還有對對象數組操作的原子類:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray。原子操作核心思想是CAS操作,然後調用底層操作系統指令來實現。
JAVA並發編程實戰怎麼樣
我不想再繼續吐槽翻譯,的確有些話理解起來有些費勁,但就內容而言,這本書當吃無愧堪稱JAVA並發領域的一朵明珠,光芒萬丈的指引着並發這條路。(如果你有能力就讀英文版的,既然要吐槽中文版,還是就事論事的好) 前年的時候看過一邊,當時覺得讀這本書的時候用個新的成語來形容就是——不明覺厲。 近兩年各種並發開始流行,其實也流行了幾十年了,可以負責任的說網上你能看到的幾乎所有中文關於JAVA並發的理解和解讀幾乎都可以在這本書上找到。 個人感覺還是應該上來介紹JMM的,這樣至少能提起很大興趣。此書的翻譯堪稱晦澀難懂,如果不是硬着頭皮讀下來,嘗試去理解,這真不是水平的問題,真難以想象花了10幾個小時愣是把這本書再次讀完了。 其實這本書讀完後你最大的收穫應該是能夠去理解那些現今相當牛逼的JAVA領域的並發庫和框架了,當然你的收穫還有就是特別小心的使用鎖,發布可見性,活躍性,性能和測試等等。 這本書包含的內容涉及之廣、之深不能全部一下子消化完,例子非常具有代表性和針對性,值得你面對並發時再次讀讀這本書,如果接觸的不多或者只是剛剛了解並發,也非常適合你對整個JAVA世界的並發領域有個認識,重讀會有更進一步的理解,JAVA的並發真是令人瞠目結舌,無法形容,強大和靈活到一定地步了,當然這份強大是用龐大付出代價的。 個人感覺看完後,真是應該再把JDK里關於並發的庫仔細讀讀。 雖然這本書是在講JAVA的並發,但是如果有別的語言經驗的同學也應該推薦讀讀,讓你了解下JAVA世界的並發是如此的精彩和複雜詭異。 雖然不能完全記住書中的細節,但建好索引就足夠了,待日後用時可以再次翻閱。
java並發集合有哪些
1、常用的並發集合類
ConcurrentHashMap:線程安全的HashMap的實現
CopyOnWriteArrayList:線程安全且在讀操作時無鎖的ArrayList
CopyOnWriteArraySet:基於CopyOnWriteArrayList,不添加重複元素
ArrayBlockingQueue:基於數組、先進先出、線程安全,可實現指定時間的阻塞讀寫,並且容量可以限制
LinkedBlockingQueue:基於鏈表實現,讀寫各用一把鎖,在高並發讀寫操作都多的情況下,性能優於ArrayBlockingQueue
2、原子類
AtomicInteger:線程安全的Integer,基於CAS(無阻塞,CPU原語),優於使用同步鎖的Integer
3、線程池
ThreadPoolExecutor:一個高效的支持並發的線程池,可以很容易的講一個實現了Runnable接口的任務放入線程池執行,但要用好這個線程池,必須合理配置corePoolSize、最大線程數、任務緩衝隊列,以及隊列滿了+線程池滿時的回絕策略,一般而言對於這些參數的配置,需考慮兩類需求:高性能和緩衝執行。
Executor:提供了一些方便的創建ThreadPoolExecutor的方法。
FutureTask:可用於異步獲取執行結果或取消執行任務的場景,基於CAS,避免鎖的使用
4、鎖
ReentrantLock:與synchronized效果一致,但是又更加靈活,支持公平/非公平鎖、支持可中斷的鎖、支持非阻塞的tryLock(可超時)、支持鎖條件等,需要手工釋放鎖,基於AbstractQueueSynchronizer
ReentrantReadWriteLock:與ReentrantLock沒有關係,採用兩把鎖,用於讀多寫少的情形
JAVA如何寫一個純並發的壓力測試
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class ConcurrentTest {
private static int thread_num = 200;
private static int client_num = 460;
private static Map keywordMap = new HashMap();
static {
try {
InputStreamReader isr = new InputStreamReader(new FileInputStream(
new File(“clicks.txt”)), “GBK”);
BufferedReader buffer = new BufferedReader(isr);
String line = “”;
while ((line = buffer.readLine()) != null) {
keywordMap.put(line.substring(0, line.lastIndexOf(“:”)), “”);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
int size = keywordMap.size();
// TODO Auto-generated method stub
ExecutorService exec = Executors.newCachedThreadPool();
// 50個線程可以同時訪問
final Semaphore semp = new Semaphore(thread_num);
// 模擬2000個客戶端訪問
for (int index = 0; index client_num; index++) {
final int NO = index;
Runnable run = new Runnable() {
public void run() {
try {
// 獲取許可
semp.acquire();
System.out.println(“Thread:” + NO);
String host = “?”;
String para = “method=getQueryResultpageNum=1pageSize=5”
+ “queryKeyWord=”
+ getRandomSearchKey(NO)
+ “questionID=-1questionIdPath=-1searchType=1”
+ “proLine=proSeries=proType=” + NO;
System.out.println(host + para);
URL url = new URL(host);// 此處填寫供測試的url
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
// connection.setRequestMethod(“POST”);
// connection.setRequestProperty(“Proxy-Connection”,
// “Keep-Alive”);
connection.setDoOutput(true);
connection.setDoInput(true);
PrintWriter out = new PrintWriter(connection
.getOutputStream());
out.print(para);
out.flush();
out.close();
BufferedReader in = new BufferedReader(
new InputStreamReader(connection
.getInputStream()));
String line = “”;
String result = “”;
while ((line = in.readLine()) != null) {
result += line;
}
// System.out.println(result);
// Thread.sleep((long) (Math.random()) * 1000);
// 釋放
System.out.println(“第:” + NO + ” 個”);
semp.release();
} catch (Exception e) {
e.printStackTrace();
}
}
};
exec.execute(run);
}
// 退出線程池
exec.shutdown();
}
private static String getRandomSearchKey(final int no) {
String ret = “”;
int size = keywordMap.size();
// int wanna = (int) (Math.random()) * (size – 1);
ret = (keywordMap.entrySet().toArray())[no].toString();
ret = ret.substring(0, ret.lastIndexOf(“=”));
System.out.println(“\t” + ret);
return ret;
}
}
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/285673.html