java容器相關問題

同步類容器?

1,這些復合操作在多線程并發地修改容器時,可能會表現出意外的行為,最經典的便是ConcurrentModificationException,原因是當容器迭代的過程中,被并發的修改了內容,這是由于早期迭代器設計的時候并沒有考慮并發修改的問題? ?增強for循環和iterator的形式不容許遍歷的時候修改元素

  • 出現java.util.ConcurrentModificationException
package com.example.core.collection;import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;public class UseSyncCollection {// 出現java.util.ConcurrentModificationExceptionpublic Collection<String> m1(Vector<String> list) {for (String temp : list) {if ("3".equals(temp)) {list.remove(temp);}}return list;}public static void main(String[] args) {Vector v = new Vector<>();v.add("1");v.add("2");v.add("3");UseSyncCollection test = new UseSyncCollection();Collection<String> ret1 = test.m1(v);System.err.println(ret1.toString());}
}
  • 出現java.util.ConcurrentModificationException?
package com.example.core.collection;import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;public class UseSyncCollection {// 出現java.util.ConcurrentModificationExceptionpublic Collection<String> m2(Vector<String> list) {Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {String temp = iterator.next();if ("3".equals(temp)) {list.remove(temp);}}return list;}public static void main(String[] args) {Vector v = new Vector<>();v.add("1");v.add("2");v.add("3");UseSyncCollection test = new UseSyncCollection();Collection<String> ret2 = test.m2(v);System.err.println(ret2.toString());}
}
  • success
package com.example.core.collection;import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;public class UseSyncCollection {//successful!普通for循環,單線程,先刪除,再返回public Collection<String> m3(Vector<String> list) {for (int i = 0; i < list.size(); i++) {if ("3".equals(list.get(i))) {list.remove(i);}}return list;}public static void main(String[] args) {Vector v = new Vector<>();v.add("1");v.add("2");v.add("3");UseSyncCollection test = new UseSyncCollection();Collection<String> ret3 = test.m3(v);System.err.println(ret3.toString());}
}

2,同步類容器: 如Vector、HashTable。 這些容器的同步功能其實都是有JDK的Collections.synchronized***等工廠方法去創建實現的。 其底層的機制無非就是用synchronized關鍵字對每個公用的方法都進行同步,或者使用Object mutex對象鎖的機制使得每次只能有一個線程訪問容器的狀態。?不滿足如今既要保證線程安全,又要追求高并發的目的

List<String> list = new ArrayList<>();
Collections.synchronizedCollection(list);

并發類容器的概念

  • jdk5.0以后提供了多種并發類容器來替代同步類容器從而改善性能。
  • 同步類容器的狀態都是串行化的。 (鎖競爭
  • 他們雖然實現了線程安全,但是嚴重降低了并發性,造成了cpu的使用率激增,在多線程環境時,嚴重降低了應用程序的吞吐量?

ConcurrentMap

  • 接口下有倆個重要的實現: ConcurrentHashMap ConcurrentSkipListMap(支持并發排序功能)
  • ConcurrentHashMap內部使用段(Segment)來表示這些不同的部分,每個段其實就是一個小的HashTable,它們有自己的鎖。
  • 只要多個修改操作發生在不同的段上,它們就可以并發進行。把一個整體分成了16個段(Segment),也就是最高支持16個線程的并發修改操作。
  • 這也是在多線程場景時減小鎖的粒度從而降低鎖競爭的一種方案。并且代碼中大多共享變量使用volatile關鍵字聲明,目的是第一時間獲取修改的內容,性能非常好。
package com.example.core.collection;import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class UseConcurrentMap {public static void main(String[] args) {ConcurrentHashMap<String, Object>map = new ConcurrentHashMap<>();map.put("k1","v1");map.put("k2","v1");map.put("k1","vv1");//如果輸入key已經存在,就會覆蓋掉原值map.putIfAbsent("k1","vvv1");//如果輸入key已經存在,不會進行任何操作for(Map.Entry<String,Object>me : map.entrySet()){System.err.println("key: "+ me.getKey()+",value:"+me.getValue());}}
}

Copy-On-Write

  • Copy-On-Write簡稱COW,是一種用于程序設計中的優化策略。
  • JDK里的COW容器有兩種: CopyOnWriteArrayList CopyOnWriteArraySet
  • COW容器非常有用,可以在非常多的并發場景中使用到。
  • CopyOnWrite容器即寫時復制的容器。 通俗的理解是當我們往一個容器添加元素的時候,不直接往當前容器添加,而是先將當前容器進行Copy,復制出一個新的容器,然后新的容器里添加元素,添加完元素之后,再將原容器的引用指向新的容器
  • 這樣做的好處是我們可以對CopyOnWrite容器進行并發的讀,而不需要加鎖,因為當前容器不會添加任何元素。 所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫不同的容器

  • A線程執行寫操作,會基于原本容器的副本(黃色的)進行操作,如果C線程此時也執行寫操作,會等待A線程的鎖釋放,再進行寫入操作。B線程執行讀操作,直接在原本的容器上面操作即可。等寫入完成之后,OrderList會將指針從原本的容器(黃色的)指向容器的副本(藍色的),而原本的容器(黃色的)會被gcc刪除
  • 如果原容器容量很大的話,就不要使用copy-on-write,因為要執行對于容器的復制,會占據內存很大的空間
  • 如果頻繁的寫入操縱,也不適合
  • 適用于讀多寫少的情況,且容器的容量也不要很大

并發Queue

  • 在并發隊列上JDK提供了兩套實現,一個是以ConcurrentLinkedQueue為代表的高性能隊列,一個是以BlockingQueue接口為代表的阻塞隊列,無論哪種都繼承自Queue接口

ConcurrentLinkedQueue

  • ConcurrentLinkedQueue:是一個適用于高并發場景下的隊列,通過無鎖的方式,實現了高并發狀態下的高性能,通常ConcurrentLinkedQueue性能好于BlockingQueue。
  • 它是一個基于鏈接節點的無界線程安全隊列。 該隊列的元素遵循先進先出的原則,頭是最先加入的,尾是最近加入的,該隊列不允許null元素。
  • ConcurrentLinkedQueue重要方法: add() 和 offer() 都是加入元素的方法 (在ConcurrentLinkedQueue中,這倆個方法沒有任何區別) poll() 和 peek() 都是取頭元素節點,區別在于前者會刪除元素,后者不會

BlockingQueue

  • offer(anObject): 表示如果可能的話, 將anObject加到BlockingQueue里,即如果BlockingQueue可以容納, 則返回true, 否則返回false.(本方法不阻塞當前執行方法的線程) 不等待
  • offer(E o, long timeout, TimeUnit unit), 可以設定等待的時間,如果在指定的時間內,還不能往隊列中加入BlockingQueue,則返回失敗。 設置等待超時時間
  • put(anObject): 把anObject加到BlockingQueue里, 如果BlockQueue沒有空間, 則調用此方法的線程被阻斷直到BlockingQueue里面有空間再繼續。堵塞等待
  • poll(long timeout, TimeUnit unit):從BlockingQueue取出一個隊首的對象,如果在指定時間內,隊列一旦有數據可取,則立即返回隊列中的數據。否則知道時間超時還沒有數據可取,返回失敗,設置等待時間
  • ?take(): 取走BlockingQueue里排在首位的對象,若BlockingQueue為空,阻斷進入等待狀態直到BlockingQueue有新的數據被加入,阻塞等待
  • drainTo(): 一次性從BlockingQueue獲取所有可用的數據對象(還可以指定獲取數據的個數),通過該方法,可以提升獲取數據效率;不需要多次分批加鎖或釋放鎖

阻塞隊列的模擬

  • 擁有固定長度承裝元素的容器
  • 計數器統計容器的容量大小
  • 當隊列里面沒有元素的時候需執行線程要等待
  • 當隊列元素已滿的時候執行線程也需要等待?? ?
package com.example.core.collection;import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;public class MyQueue {// 創建隊列容器private final LinkedList<Object> list = new LinkedList<>();// 創建計數器countprivate final AtomicInteger count = new AtomicInteger(0);//單個服務的原子性,保證數據的一致性private final int maxSize;//最大容量的限制private final int minSize = 0;//最小容量的限制private final Object lock = new Object();//鎖public MyQueue(int maxSize){this.maxSize = maxSize;}public void put(Object obj){synchronized (lock){while(count.get() == maxSize){try{lock.wait();}catch(InterruptedException e){e.printStackTrace();}}//  添加新的元素進入容器中list.add(obj);count.getAndIncrement();//i++System.err.println("元素"+obj+"已經添加到容器中");//進行喚醒可能正在等待的take方法操作中的線程,當take來取數值時,容器為空,take進行等待,當數據放入,通知take取數lock.notify();}}public Object take(){Object temp = null;synchronized (lock){while(count.get() == minSize){try{lock.wait();}catch (InterruptedException e){e.printStackTrace();}}temp = list.removeFirst();//移除第一個元素count.getAndDecrement();//i--System.err.println("元素"+temp+"已經從容器中取走");//進行喚醒可能正在等待的put方法操作線程,當put方法往容器里面放數值,但是容器已滿,put進入等待,當take取走數據,喚醒put來存入數據lock.notify();}return temp;}public int  size(){return count.get();}public List<Object> getQueueList(){return list;}
}

編寫MyQueueTest.java的測試代碼

package com.example.core.collection;public class MyQueueTest {public static void main(String[] args) throws Exception{MyQueue mq = new MyQueue(5);mq.put("a");mq.put("b");mq.put("c");mq.put("d");mq.put("e");System.out.println("當前元素的個數:"+mq.size());Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {mq.put("f");mq.put("g");}},"t1");Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {try{Thread.sleep(1000);Object o1 = mq.take();Thread.sleep(1000);Object o2 = mq.take();}catch(InterruptedException e){e.printStackTrace();}}},"t2");t1.start();Thread.sleep(1000);t2.start();Thread.sleep(5000);System.out.println(mq.getQueueList().toString());}
}
/*
輸出結果如下
元素a已經添加到容器中
元素b已經添加到容器中
元素c已經添加到容器中
元素d已經添加到容器中
元素e已經添加到容器中
當前元素的個數:5
元素a已經從容器中取走
元素f已經添加到容器中
元素b已經從容器中取走
元素g已經添加到容器中
[c, d, e, f, g]
*/

ArrayBlockingQueue

  • ArrayBlockingQueue:基于數組的阻塞隊列實現
  • 在ArrayBlockingQueue內部,維護了一個定長數組,以便緩存隊列中的數據對象,其內部沒實現讀寫分離,也就意味著生產和消費不能完全并行,長度是需要定義的,可以指定先進先出或者先進后出,也叫有界隊列,在很多場合非常適合使用。

高性能無阻塞無界隊列

package com.example.core.collection;import java.util.concurrent.ConcurrentLinkedQueue;public class UseBlockingQueue {public static void main(String[] args) throws Exception{//高性能的無阻塞的無界限隊列ConcurrentLinkedQueue<String> clq = new ConcurrentLinkedQueue<>();clq.offer("a");clq.add("b");clq.add("c");clq.add("d");System.out.println("從容器頭部取出元素"+clq.poll());//從頭部取出元素,并且從容器本身移除System.out.println("容器的長度"+clq.size());System.out.println("從容器的頭部取出元素"+clq.peek());//從頭部取出元素,并且不會從容器本身移除System.out.println("容器的長度"+clq.size());}
}

基于阻塞-有界隊列

package com.example.core.collection;import java.util.Iterator;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;public class UseBlockingQueue {public static void main(String[] args) throws Exception{//基于阻塞的有界隊列ArrayBlockingQueue<String> abq = new ArrayBlockingQueue<>(5);abq.put("a");abq.add("b");abq.add("c");abq.add("d");abq.add("e");System.out.println(abq.offer("f",2, TimeUnit.SECONDS));ArrayBlockingQueue<String> abq2 = new ArrayBlockingQueue<>(5);abq.drainTo(abq2,3);for(Iterator iterator = abq2.iterator();iterator.hasNext();){String string = (String)iterator.next();System.out.println("元素"+string);}}
}

LinkedBlockingQueue

  • 基于鏈表的阻塞隊列 同ArrayBlockingQueue類似,其內部也維持著一個數據緩沖隊列(該隊列由一個鏈表構成)
  • LinkedBlockingQueue之所以能夠高效的處理并發數據,是因為其內部實現采用分離鎖(讀寫分離兩個鎖),從而實現生產者和消費者操作的完全并行運行。他是一個無界隊列
 LinkedBlockingQueue<String> lbq = new LinkedBlockingQueue<>();

SynchronousQueue?

  • 一種沒有緩沖的隊列
  • 生產者產生的數據直接會被消費者獲取并消費

  • A線程一直等待B線程的輸入,B產生的數據被A消費,SynchronousQueue只是做一個中轉,不負責存儲
package com.example.core.collection;import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.*;public class UseBlockingQueue {public static void main(String[] args) throws Exception{//不能存放任何元素的 阻塞隊列SynchronousQueue<String>sq = new SynchronousQueue<>();new Thread(new Runnable() {@Overridepublic void run() {try{System.out.println("元素內容:"+sq.take());}catch (InterruptedException e){e.printStackTrace();}}},"t1").start();new Thread(new Runnable() {@Overridepublic void run() {sq.add("a");}},"t2").start();}
}

PriorityBlockingQueue

  • 基于優先級的阻塞隊列
  • 優先級的判斷通過構造函數傳入的Compator對象來決定,也就是說傳入隊列的對象必須實現Comparable接口,在實現PriorityBlockingQueue時,內部控制線程同步的鎖采用的是公平鎖,他也是一個無界的隊列
package com.example.core.collection;import java.util.concurrent.PriorityBlockingQueue;public class UsePriorityBlockingQueue {public static void main(String[] args) throws InterruptedException{PriorityBlockingQueue<Node> pdq = new PriorityBlockingQueue<Node>();Node n3 = new Node(3,"node3");Node n4 = new Node(4,"node4");Node n2 = new Node(2,"node2");Node n1 = new Node(1,"node1");pdq.add(n4);pdq.add(n3);pdq.add(n1);pdq.add(n2);System.out.println("0 容器為:"+pdq);System.out.println("1 獲取元素:"+pdq.take().getId());System.out.println("1 容器為  :"+pdq);System.out.println("2 獲取元素:"+pdq.take().getId());System.out.println("2 容器為  :"+pdq);System.out.println("3 獲取元素:"+pdq.take().getId());System.out.println("3 容器為  :"+pdq);System.out.println("4 獲取元素為:"+pdq.take().getId());}
}
package com.example.core.collection;public class Node implements Comparable<Node>{private int id;private String name;public Node(){}public Node(int id,String name){super();this.id = id;this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic int compareTo(Node node){return this.id > node.id ? 1 : (this.id < node.id ? -1 : 0);}public String toString(){return this.id + ":" + this.name;}
}

DelayQueue

  • 帶有延遲時間的Queue
  • 其中的元素只有當其指定的延遲時間到了,才能夠從隊列中獲取到該元素。DelayQueue中的元素必須實現Delayed接口,DelayQueue是一個沒有大小限制的隊列,應用場景很多,比如對緩存超時的數據進行移除、 任務超時處理、空閑連接的關閉等等
package com.example.core.collection;import java.util.concurrent.DelayQueue;public class Wangba implements Runnable{private DelayQueue<WangMin> delayQueue = new DelayQueue<WangMin>();public boolean start = true;//表示網吧營業public void startMachine(String id,String name,int money){WangMin wm = new WangMin(id,name,System.currentTimeMillis()+money * 1000);System.out.println("網名:"+ name +",身份證: "+id+",繳費:"+money+"元,開始上網");delayQueue.add(wm);}public void overMachine(WangMin wm){System.out.println("網名:"+wm.getName()+",身份證:"+wm.getId()+",已經到了下機時間了");}@Overridepublic void run(){while (start){try{WangMin wm = delayQueue.take();overMachine(wm);}catch(InterruptedException e){e.printStackTrace();}}}public static void main(String[] args) {Wangba wangba = new Wangba();System.out.println("網吧正常營業");Thread yingye = new Thread(wangba);yingye.start();wangba.startMachine("001","張三",2);wangba.startMachine("001","李四",4);wangba.startMachine("001","王五",7);}
}
package com.example.core.collection;import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;public class WangMin implements Delayed {private String id;private String name;private long endTime;//上網截止日期private final TimeUnit timeUnit = TimeUnit.SECONDS;@Overridepublic String toString() {return "WangMin{" +"id='" + id + '\'' +", name='" + name + '\'' +", endTime=" + endTime +'}';}public WangMin(){}public WangMin(String id,String name,long endTime){this.id = id;this.name = name;this.endTime = endTime;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public long getEndTime() {return endTime;}public void setEndTime(long endTime) {this.endTime = endTime;}public TimeUnit getTimeUnit() {return timeUnit;}//用來判斷是否到達下機時間@Overridepublic long getDelay(TimeUnit unit){return endTime - System.currentTimeMillis();}@Overridepublic int compareTo(Delayed delayed){WangMin w = (WangMin)delayed;return this.getDelay(timeUnit) - w.getDelay(timeUnit) > 0 ? 1 : -1;}
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/447315.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/447315.shtml
英文地址,請注明出處:http://en.pswp.cn/news/447315.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

趣文:如果編程語言是車

C語言是全能手&#xff0c;小巧&#xff0c;強大&#xff0c;所向披靡&#xff0c;可靠&#xff0c;任何事情都能對付。 C是新的C&#xff0c;雙倍的能力&#xff0c;雙倍的尺寸&#xff0c;適應險惡的環境&#xff0c;但是你如果沒練好就去駕駛&#xff0c;很可能會撞車。 C#是…

Java 線程安全

線程安全 線程安全概念&#xff1a;當多個線程訪問某一個類&#xff08;對象或方法&#xff09;時&#xff0c;這個類始終都能表現出正確的行為&#xff0c;那么這個類&#xff08;對象或方法&#xff09;就是線程安全的。synchronized&#xff1a;可以在任意對象及方法上加鎖…

開發者應該了解的API技術清單!

摘要&#xff1a;有人說&#xff0c;有API的地方就有App&#xff0c;借助這些API開發者輕松構建出一款應用&#xff0c;極大地提高開發效率和開發質量。文中整理了一份API服務清單&#xff0c;內容涵蓋&#xff1a;監控/調試、 CDN 、數據庫、儀表盤、支付、通信等方面&#xf…

提高程序員職場價值的10大技巧

如果你已經是個很牛叉的程序員&#xff0c;但是依然覺得覺得還不夠的話&#xff0c;歡迎閱讀此文。本文旨在幫助各位更上一層樓。 你是不是覺得自己已經掌握了所有的編程技巧&#xff1f;別太自以為是了&#xff01; 會寫代碼的確很重要&#xff0c;但是要拿到更好薪水&#…

google python的風格規范

點擊鏈接&#xff0c;查看內容

IT人應當知道的10個行業小內幕

如果你打算從事IT行業或剛進入這個行業&#xff0c;也許本文下面的小內幕會嚇到你&#xff0c;因為這些事平常都不會公開討論的。如果你是IT資深人士&#xff0c;或許你已經遇到其中的大部分了。如果你愿意&#xff0c;請一起來參與討論吧。 這些內幕大多數是針對網絡管理員、…

Volatile原子性一致性JVM指令重排

概念 Volatile概念&#xff1a;Volatile關鍵字的主要作用是使變量在多個線程間可見。作用&#xff1a; 在多線程間可以進行變量的變更&#xff0c;使得線程間進行數據的共享可見 阻止指令重排序&#xff0c;happens-before package com.example.core.cas;import com.example.c…

python修改文件內容,不需要read,write多個動作。

python 要修改文件內容&#xff0c;常用 是先read&#xff0c;后write &#xff0c; 再 rename&#xff0c;很不爽。 比如&#xff1a;需要 把 yuv_dir "../HD/" # "H:/HD_Master/1080i25/" 改為 yuv_dir "C:/HD/" # "H:…

Atomic系列類

Atomic系列類別 Atomic系列類封裝了一系列的基礎類型和對象操作&#xff0c;其主要目的就是為了實現原子性&#xff0c;主要核心類如下 AtomicIntegerAtomicLongAtomicBooleanAtomicIntegerArrayAtomicLongArrayAtomicReference 原子性的引用對象在對Atomic類操作的時候&…

python 系統學習筆記(十二)---os os.path os.walk

得到當前工作目錄&#xff0c;即當前 Python腳本工作的目錄路徑: os.getcwd() 返回指定目錄下的所有文件和目錄名:os.listdir()函數用來刪除一個文件:os.remove()刪除多個目錄&#xff1a;os.removedirs&#xff08;r“c&#xff1a;\python”&#xff09;檢驗給出的路徑是否是…

Java JUC工具類--CountDownLatch

CountDownLatch&#xff1a;用于監聽某些初始化操作&#xff0c;并且線程進行阻塞&#xff0c;等初始化執行完畢后&#xff0c;通知主線程繼續工作執行 package com.example.core.juc;import java.util.concurrent.CountDownLatch;public class UseCountDownLatch {public stat…

Java JUC工具類--CyclicBarrier

CyclicBarrier&#xff1a;柵欄的概念&#xff0c;多線程的進行阻塞&#xff0c;等待某一個臨界值條件滿足后&#xff0c;同時執行 類比&#xff1a;每個線程代表一個跑步運動員&#xff0c;當運動員都準備好后&#xff0c;才一起出發&#xff0c;只要有一個人沒有準備好&#…

人生感悟:人生像吃自助餐

問我怎樣管理欲望&#xff0c;過簡單生活?我的答案是&#xff1a;你要先學會品味人生&#xff0c;品味的同義詞&#xff0c;就叫做體悟內涵。 人為什么有這么多欲望?其實&#xff0c;我們每個人在一個社會&#xff0c;就像進入一個自助餐(buffet)店&#xff0c;食物非常的多…

Java JUC工具類--Future

Future模式&#xff0c;也是非常經典的設計模式&#xff0c;這種模式主要就利用空間換時間的概念&#xff0c;也就是說異步執行&#xff08;需要開啟一個新的線程&#xff09;在互聯網高并發的應用服務中&#xff0c;我們隨處可見這種理念和代碼&#xff0c;主要就是使用了這種…

職場與生活 八條原則 讓你不再浪費時間和提高效率

Heidi Roizen女士一度是硅谷人人爭相學習的典范。她曾創辦自己的公司并管理了14年之久。后來&#xff0c;她擔任蘋果公司主管開發者關系的高級副總裁。現在&#xff0c;她是DFJ Venture的一位風投家&#xff0c;她還在斯坦福主講一門名叫??“企業家精神??”的課程。她幾乎認…

Java JUC工具類--Exchanger

Exchanger Exchanger用于進行線程間的數據交換&#xff0c;它提供一個同步點&#xff0c;在這個同步點&#xff0c;兩個線程可以交換彼此的數據兩個線程通過exchange方法交換數據&#xff0c;如果一個線程先執行exchange方法&#xff0c;它會一直等待第二個線程也執行exchang…

爸爸的素質決定孩子飛多高,爸爸們請反復看!!!

好父親等于200個好老師&#xff0c;當爹的都好好看看&#xff0c;以后孩子不給力別怨別人! 孩子是父親的影子&#xff0c;希望每個閱讀完全文的父親&#xff0c;都能成為一個好父親。 NO.1爸爸是孩子最好的老師 爸爸的素質有多高&#xff0c;孩子就能飛多高 用理性的父愛幫…

Java JUC工具類--ForkJoin

ForkJoin Fork/Join框架是JAVA7提供的一個用于并行執行任務的框架&#xff0c;是一個把大任務分割成若干個小任務&#xff0c;最終匯總每個小任務結果后得到大任務結果的框架Fork/Join中兩個重要的類 ForkJoinTask&#xff1a;使用該框架&#xff0c;需要創建一個ForkJoin任務…

修復bug的12個關鍵步驟

要多少時間才能修復bug&#xff0c;事先是很難知道的&#xff0c;特別是如果你和這些代碼還素不相識的話&#xff0c;情況就更加撲朔迷離了。James Shore在《The Art of Agile 》一書中&#xff0c;明確指出要想修復問題得先知道問題的所在。而我們之所以無法準確估計時間是因為…