在 java 5.0 提供了 java.util.concurrent (簡(jiǎn)稱JUC )包,在此包中增加了在并發(fā)編程中很常用的實(shí)用工具類,用于定義類似于線程的自定義子系統(tǒng),包括線程池、異步 IO 和輕量級(jí)任務(wù)框架。提供可調(diào)的、靈活的線程池。還提供了設(shè)計(jì)用于多線程上下文中的 Collection 實(shí)現(xiàn)等。
內(nèi)存可見性
內(nèi)存可見性(Memory Visibility)是指當(dāng)某個(gè)線程正在使用對(duì)象狀態(tài)而另一個(gè)線程在同時(shí)修改該狀態(tài),需要確保當(dāng)一個(gè)線程修改了對(duì)象狀態(tài)后,其他線程能夠看到發(fā)生的狀態(tài)變化。
可見性錯(cuò)誤是指當(dāng)讀操作與寫操作在不同的線程中執(zhí)行時(shí),我們無法確保執(zhí)行讀操作的線程能適時(shí)地看到其他線程寫入的值,有時(shí)甚至是根本不可能的事情。
我們可以通過同步來保證對(duì)象被安全地發(fā)布。除此之外我們也可以使用一種更加輕量級(jí)的 volatile 變量。
volatile 關(guān)鍵字
Java 提供了一種稍弱的同步機(jī)制,即 volatile 變量,用來確保將變量的更新操作通知到其他線程,可以保證內(nèi)存中的數(shù)據(jù)可見。可以將 volatile 看做一個(gè)輕量級(jí)的鎖,但是又與鎖有些不同:
對(duì)于多線程,不是一種互斥關(guān)系不能保證變量狀態(tài)的“原子性操作”public class TestVolatile { public static void main(String[] args){ ThreadDemo td=new ThreadDemo(); new Thread(td).start(); while(true){ if(td.isFlag()){ System.out.二、原子變量 、CAS原子變量:jdk1.5 后 java.util.concurrent.atomic 類的小工具包,支持在單個(gè)變量上解除鎖的線程安全編程,包下提供了常用的原子變量: - AtomicBoolean 、AtomicInteger 、AtomicLong 、 AtomicReference - AtomicIntegerArray 、AtomicLongArray - AtomicMarkableReference - AtomicReferenceArray - AtomicStampedReference
1.類中的變量都是volatile類型:保證內(nèi)存可見性 2.使用CAS算法:保證數(shù)據(jù)的原子性
CAS (Compare-And-Swap) 是一種硬件對(duì)并發(fā)的支持,針對(duì)多處理器操作而設(shè)計(jì)的處理器中的一種特殊指令,用于管理對(duì)共享數(shù)據(jù)的并發(fā)訪問。 CAS 是一種無鎖的非阻塞算法的實(shí)現(xiàn)。 CAS包含三個(gè)操作數(shù): 內(nèi)存值 V 預(yù)估值 A 更新值 B 當(dāng)且僅當(dāng)V==A時(shí),B的值才更新給A,否則將不做任何操作。
public class TestAtomicDemo { public static void main(String[] args) { AtomicDemo ad = new AtomicDemo(); for (int i = 0; i < 10; i++) { new Thread(ad).start(); } }}class AtomicDemo implements Runnable{// private volatile int serialNumber = 0; private AtomicInteger serialNumber = new AtomicInteger(0); @Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { } System.out.println(getSerialNumber()); } public int getSerialNumber(){ return serialNumber.getAndIncrement();//i++ 實(shí)際是int temp=i;i=i+1;i=temp; 需要原子性操作 }}使用synchronized方法模擬CAS 算法,實(shí)際是由硬件機(jī)制完成的,用10個(gè)線程代表對(duì)內(nèi)存中數(shù)據(jù)的10次修改請(qǐng)求。只有上個(gè)線程修改完,這個(gè)線程從內(nèi)存中獲取的內(nèi)存值當(dāng)成期望值,才等于內(nèi)存值,才能對(duì)內(nèi)存值進(jìn)行修改。
public class TestCompareAndSwap { public static void main(String[] args) { final CompareAndSwap cas=new CompareAndSwap(); for(int i=0;i<10;i++){ new Thread(new Runnable(){ @Override public void run() { int expectedValue=cas.get(); boolean b=cas.compareAndSwap(expectedValue, (int)(Math.random()*101)); System.out.println(b); } }).start(); } }}class CompareAndSwap{ private int value;//內(nèi)存值 //獲取內(nèi)存值 public synchronized int get(){ return value; } //比較 public synchronized boolean compareAndSwap(int expectedValue,int newValue){ int oldValue=value;//線程讀取內(nèi)存值,與預(yù)估值比較 if(oldValue==expectedValue){ this.value=newValue; return true; } return false; }}HashMap 線程不安全 Hashtable 內(nèi)部采用獨(dú)占鎖,線程安全,但效率低 ConcurrentHashMap同步容器類是java5 新增的一個(gè)線程安全的哈希表,效率介于HashMap和Hashtable之間。內(nèi)部采用“鎖分段”機(jī)制。
java.util.concurrent 包還提供了設(shè)計(jì)用于多線程上下文中的Collection實(shí)現(xiàn):
當(dāng)期望許多線程訪問一個(gè)給定 collection 時(shí), ConcurrentHashMap 通常優(yōu)于同步的 HashMap, ConcurrentSkipListMap 通常優(yōu)于同步的 TreeMap ConcurrentSkipListSet通常優(yōu)于同步的 TreeSet.
當(dāng)期望的讀數(shù)和遍歷遠(yuǎn)遠(yuǎn)大于列表的更新數(shù)時(shí), CopyOnWriteArrayList 優(yōu)于同步的 ArrayList。因?yàn)槊看翁砑訒r(shí)都會(huì)進(jìn)行復(fù)制,開銷非常的大,并發(fā)迭代操作多時(shí) ,選擇。
CountDownLatch 一個(gè)同步輔助類,在完成一組正在其他線程中執(zhí)行的操作之前,它允許一個(gè)或多個(gè)線程一直等待。
閉鎖可以延遲線程的進(jìn)度直到其到達(dá)終止?fàn)顟B(tài),閉鎖可以用來確保某些活動(dòng)直到其他活動(dòng)都完成才繼續(xù)執(zhí)行: ? 確保某個(gè)計(jì)算在其需要的所有資源都被初始化之后才繼續(xù)執(zhí)行; ? 確保某個(gè)服務(wù)在其依賴的所有其他服務(wù)都已經(jīng)啟動(dòng)之后才啟動(dòng); ? 等待直到某個(gè)操作所有參與者都準(zhǔn)備就緒再繼續(xù)執(zhí)行。
/* * CountDownLatch:閉鎖,在完成某些運(yùn)算時(shí),只有其他所有線程的運(yùn)算全部完成,當(dāng)前運(yùn)算才繼續(xù)執(zhí)行 */public class TestCountDownLatch { public static void main(String[] args) { final CountDownLatch latch=new CountDownLatch(50); LatchDemo ld=new LatchDemo(latch); long start=System.currentTimeMillis(); for(int i=0;i<50;i++){ new Thread(ld).start(); } try { latch.await(); //直到50個(gè)人子線程都執(zhí)行完,latch的值減到0時(shí),才往下執(zhí)行 } catch (InterruptedException e) { e.printStackTrace(); } long end=System.currentTimeMillis(); System.out.println("耗費(fèi)時(shí)間為:"+(end-start)); }}class LatchDemo implements Runnable{ private CountDownLatch latch; public LatchDemo(CountDownLatch latch){ this.latch=latch; } @Override public void run() { try{ for(int i=0;i<50000;i++){ if(i%2==0){ System.out.println(i); } } }finally{ latch.countDown();//latch的值減一 } }}Java 5.0 在 java.util.concurrent 提供了一個(gè)新的創(chuàng)建執(zhí)行線程的方式:Callable 接口
實(shí)現(xiàn)Callable 接口,相較于實(shí)現(xiàn) Runnable接口的方式,方法可以有返回值,并且可以拋出異常。
Callable 需要依賴FutureTask ,用于接收返回值,F(xiàn)utureTask 也可以用作閉鎖。
/* * 一、創(chuàng)建執(zhí)行線程的方式三:實(shí)現(xiàn)Callable接口。相較于實(shí)現(xiàn)Runnable接口的方式,方法可以有返回值,并且可以拋出異常。 * 二、執(zhí)行Callable方式,需要FutureTask實(shí)現(xiàn)類的支持,用于接收運(yùn)算結(jié)果。FutureTask是Future接口的實(shí)現(xiàn)類 */public class TestCallable { public static void main(String[] args) { ThreadDemo2 td=new ThreadDemo2(); //1.執(zhí)行Callable方式,需要FutureTask實(shí)現(xiàn)類的支持,用于接收運(yùn)行結(jié)果。 FutureTask<Integer> result=new FutureTask<>(td); new Thread(result).start(); //2.接收線程運(yùn)算后的結(jié)果 try { Integer sum = result.get();//FutureTask 可用于 閉鎖 當(dāng)子線程執(zhí)行完畢,才會(huì)執(zhí)行此后語句 System.out.println(sum); System.out.println("----------------------"); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }}class ThreadDemo2 implements Callable<Integer>{ @Override public Integer call() throws Exception { int sum=0; for(int i=0;i<=100000;i++){ sum+=i; } return sum; }}在 Java 5.0 之前,協(xié)調(diào)共享對(duì)象的訪問時(shí)可以使用的機(jī)制只有 synchronized 和 volatile 。Java 5.0 后增加了一些新的機(jī)制,但并不是一種替代內(nèi)置鎖的方法,而是當(dāng)內(nèi)置鎖不適用時(shí),作為一種可選擇的高級(jí)功能。
ReentrantLock 實(shí)現(xiàn)了 Lock 接口,并提供了與synchronized 相同的互斥性和內(nèi)存可見性。但相較于synchronized 提供了更高的處理鎖的靈活性。
/* * 一、用于解決多線程安全問題的方式: * synchronized:隱式鎖 * 1、同步代碼塊 * 2、同步方法 * jdk 1.5后 * 3、同步鎖 Lock * 注意:是一個(gè)顯式鎖,通過lock()方式上鎖,必須通過unlock()方法釋放鎖 */public class TestLock { public static void main(String[] args) { Ticket ticket=new Ticket(); new Thread(ticket,"1號(hào)窗口").start(); new Thread(ticket,"2號(hào)窗口").start(); new Thread(ticket,"3號(hào)窗口").start(); }}class Ticket implements Runnable{ private int tick=100; private Lock lock=new ReentrantLock(); @Override public void run() { while(true){ lock.lock(); try{ if(tick>0){ try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"完成售票為:"+--tick); } else{ break; } }finally{ lock.unlock();//釋放鎖一定要放在finally里,保證一定執(zhí)行 } } }}/* * 生產(chǎn)者和消費(fèi)者案例,優(yōu)化,防止出現(xiàn)虛假喚醒,線程無法停止 */public class TestProductorAndConsumer { public static void main(String[] args) { Clerk clerk=new Clerk(); Productor pro=new Productor(clerk); Consumer cus=new Consumer(clerk); new Thread(pro,"生產(chǎn)者 A").start(); new Thread(cus,"消費(fèi)者 B").start(); new Thread(pro,"生產(chǎn)者 C").start(); new Thread(cus,"消費(fèi)者 D").start(); }}//店員 假如只有一個(gè)商品位置class Clerk{ private int product=0; //進(jìn)貨 public synchronized void get(){ while(product>=1){//為了避免虛假喚醒問題,應(yīng)該總是使用在循環(huán)中 System.out.println("產(chǎn)品已滿!"); try{ this.wait(); }catch(InterruptedException e){ } } System.out.println(Thread.currentThread().getName()+" : "+ ++product); this.notifyAll(); } //賣貨 public synchronized void sale(){ while(product<=0){ System.out.println("缺貨!"); try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+" : "+ --product); this.notifyAll(); }}//生產(chǎn)者class Productor implements Runnable{ private Clerk clerk; public Productor(Clerk clerk){ this.clerk=clerk; } @Override public void run() { for(int i=0;i<20;i++){ try{ Thread.sleep(200); }catch(InterruptedException e){ } clerk.get(); } }}//消費(fèi)者class Consumer implements Runnable{ private Clerk clerk; public Consumer(Clerk clerk){ this.clerk=clerk; } @Override public void run() { for(int i=0;i<20;i++){ clerk.sale(); } }}Condition 接口描述了可能會(huì)與鎖有關(guān)聯(lián)的條件變量。這些變量在用法上與使用 Object.wait 訪問的隱式監(jiān)視器類似,但提供了更強(qiáng)大的功能。需要特別指出的是,單個(gè) Lock 可能與多個(gè) Condition 對(duì)象關(guān)聯(lián)。為了避免兼容性問題,Condition 方法的名稱與對(duì)應(yīng)的 Object 版本中的不同。
在 Condition 對(duì)象中,與 wait、notify 和 notifyAll 方法對(duì)應(yīng)的分別是await、signal 和 signalAll。
Condition 實(shí)例實(shí)質(zhì)上被綁定到一個(gè)鎖上。要為特定 Lock 實(shí)例獲得Condition 實(shí)例,請(qǐng)使用其 newCondition() 方法。
public class TestProductorAndConsumerForLock { public static void main(String[] args) { Clerk clerk=new Clerk(); Productor pro=new Productor(clerk); Consumer cus=new Consumer(clerk); new Thread(pro,"生產(chǎn)者 A").start(); new Thread(cus,"消費(fèi)者 B").start(); new Thread(pro,"生產(chǎn)者 C").start(); new Thread(cus,"消費(fèi)者 D").start(); }}//店員 假如只有一個(gè)商品位置class Clerk{ private int product=0; private Lock lock=new ReentrantLock(); private Condition condition=lock.newCondition(); //進(jìn)貨 public void get(){ lock.lock(); try{ while(product>=1){//為了避免虛假喚醒問題,應(yīng)該總是使用在循環(huán)中 System.out.println("產(chǎn)品已滿!"); try{ condition.await();//this.wait(); }catch(InterruptedException e){ } } System.out.println(Thread.currentThread().getName()+" : "+ ++product); condition.signalAll();//this.notifyAll(); }finally{ lock.unlock(); } } //賣貨 public void sale(){ lock.lock(); try{ while(product<=0){ System.out.println("缺貨!"); try { condition.await();//this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+" : "+ --product); condition.signalAll();//this.notifyAll(); }finally{ lock.unlock(); } }}//生產(chǎn)者class Productor implements Runnable{ private Clerk clerk; public Productor(Clerk clerk){ this.clerk=clerk; } @Override public void run() { for(int i=0;i<20;i++){ try{ Thread.sleep(200); }catch(InterruptedException e){ } clerk.get(); } }}//消費(fèi)者class Consumer implements Runnable{ private Clerk clerk; public Consumer(Clerk clerk){ this.clerk=clerk; } @Override public void run() { for(int i=0;i<20;i++){ clerk.sale(); } }}編寫一個(gè)程序,開啟 3 個(gè)線程,這三個(gè)線程的 ID 分別為A、B、C,每個(gè)線程將自己的 ID 在屏幕上打印 10 遍,要求輸出的結(jié)果必須按順序顯示。如:ABCABCABC…… 依次遞歸
public class TestABCAlternate { public static void main(String[] args) { AlternateDemo ad=new AlternateDemo(); new Thread(new Runnable(){ @Override public void run() { for(int i=1;i<=20;i++){ ad.loopA(i); } } },"A").start(); new Thread(new Runnable(){ @Override public void run() { for(int i=1;i<=20;i++){ ad.loopB(i); } } },"B").start(); new Thread(new Runnable(){ @Override public void run() { for(int i=1;i<=20;i++){ ad.loopC(i); System.out.println("-----------------------------------"); } } },"C").start(); }}class AlternateDemo{ private int number=1;//當(dāng)前正在執(zhí)行線程的標(biāo)記 private Lock lock=new ReentrantLock(); private Condition condition1=lock.newCondition(); private Condition condition2=lock.newCondition(); private Condition condition3=lock.newCondition(); /* * @param totalLoop:循環(huán)第幾輪 */ public void loopA(int totalLoop){ lock.lock(); try{ //1.判斷 if(number!=1){ condition1.await(); } //2.打印 System.out.println(Thread.currentThread().getName()+"/t"+totalLoop); //3.喚醒 number=2; condition2.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally{ lock.unlock(); } } public void loopB(int totalLoop){ lock.lock(); try{ //1.判斷 if(number!=2){ condition2.await(); } //2.打印 System.out.println(Thread.currentThread().getName()+"/t"+totalLoop); //3.喚醒 number=3; condition3.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally{ lock.unlock(); } } public void loopC(int totalLoop){ lock.lock(); try{ //1.判斷 if(number!=3){ condition3.await(); } //2.打印 System.out.println(Thread.currentThread().getName()+"/t"+totalLoop); //3.喚醒 number=1; condition1.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally{ lock.unlock(); } }}ReadWriteLock 維護(hù)了一對(duì)相關(guān)的鎖,一個(gè)用于只讀操作,另一個(gè)用于寫入操作。只要沒有 writer,讀取鎖可以由多個(gè) reader 線程同時(shí)保持。寫入鎖是獨(dú)占的。
ReadWriteLock 讀取操作通常不會(huì)改變共享資源,但執(zhí)行寫入操作時(shí),必須獨(dú)占方式來獲取鎖。對(duì)于讀取操作占多數(shù)的數(shù)據(jù)結(jié)構(gòu)。 ReadWriteLock 能提供比獨(dú)占鎖更高的并發(fā)性。而對(duì)于只讀的數(shù)據(jù)結(jié)構(gòu),其中包含的不變性可以完全不需要考慮加鎖操作。
/* * 1.ReadWriteLock:讀寫鎖 * 寫寫|讀寫 需要"互斥" * 讀讀 不需要"互斥" */public class TestReadWriteLock { public static void main(String[] args) { ReadWriteLockDemo rw=new ReadWriteLockDemo(); new Thread(new Runnable() { @Override public void run() { rw.set((int)(Math.random()*101)); } },"Write").start(); for(int i=0;i<100;i++){ new Thread(new Runnable() { @Override public void run() { rw.get(); } }).start(); } }}class ReadWriteLockDemo{ private int number=0; private ReadWriteLock lock=new ReentrantReadWriteLock(); //讀 public void get(){ lock.readLock().lock();//上鎖 try{ System.out.println(Thread.currentThread().getName()+" : "+number); }finally{ lock.readLock().unlock();//釋放鎖 } } //寫 public void set(int number){ lock.writeLock().lock(); try{ System.out.println(Thread.currentThread().getName()); this.number=number; }finally{ lock.writeLock().unlock(); } }}獲取線程第四種方法。 線程池可以解決兩個(gè)不同問題:由于減少了每個(gè)任務(wù)調(diào)用的開銷,它們通常可以在執(zhí)行大量異步任務(wù)時(shí)提供增強(qiáng)的性能,并且還可以提供綁定和管理資源(包括執(zhí)行任務(wù)集時(shí)使用的線程)的方法。每個(gè) ThreadPoolExecutor 還維護(hù)著一些基本的統(tǒng)計(jì)數(shù)據(jù),如完成的任務(wù)數(shù)。
為了便于跨大量上下文使用,此類提供了很多可調(diào)整的參數(shù)和擴(kuò)展鉤子 (hook)。但是,強(qiáng)烈建議程序員使用較為方便的 Executors 工廠方法 :
Executors.newCachedThreadPool()(無界線程池,可以進(jìn)行自動(dòng)線程回收)Executors.newFixedThreadPool(int)(固定大小線程池)Executors.newSingleThreadExecutor()(單個(gè)后臺(tái)線程)它們均為大多數(shù)使用場(chǎng)景預(yù)定義了設(shè)置。
/* * 一、線程池:提供了一個(gè)線程隊(duì)列,隊(duì)列中保存著所有等待狀態(tài)的線程。避免了創(chuàng)建與銷毀額外開銷,提高了響應(yīng)的速度。 * 二、線程池的體系結(jié)構(gòu): * java.util.concurrent.Executor:負(fù)責(zé)線程的使用與調(diào)度的根接口 * |--**ExecutorService 子接口:線程池的主要接口 * |--ThreadPoolExecutor 線程池的實(shí)現(xiàn)類 * |--ScheduledExecutorService 子接口:負(fù)責(zé)線程的調(diào)度 * |--ScheduledThreadPoolExecutor:繼承ThreadPoolExecutor,實(shí)現(xiàn)ScheduledExecutorService接口 * 三、工具類:Executors * 方法有: * ExecutorService newFixedThreadPool(): 創(chuàng)建固定大小的線程池 * ExecutorService newCachedThreadPool():緩存線程池,線程池的數(shù)量不固定,可以根據(jù)需要自動(dòng)的更改數(shù)量。 * ExecutorService newSingleThreadExecutor():創(chuàng)建單個(gè)線程池。線程池中只有一個(gè)線程 * * ScheduledExecutorService newScheduledThreadPool():創(chuàng)建固定大小的線程,可以延遲或定時(shí)的執(zhí)行任務(wù)。 * */public class TestThreadPool { public static void main(String[] args) { //1.創(chuàng)建線程池 ExecutorService pool=Executors.newFixedThreadPool(5); List<Future<Integer>> list=new ArrayList<>(); for (int i = 0; i < 10; i++) { Future<Integer> future=pool.submit(new Callable<Integer>(){ @Override public Integer call() throws Exception { int sum=0; for(int i=0;i<=100;i++){ sum+=i; } return sum; } }); list.add(future); } pool.shutdown(); for(Future<Integer> future:list){ try { System.out.println(future.get()); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } }}Fork/Join 框架:就是在必要的情況下,將一個(gè)大任務(wù),進(jìn)行拆分(fork)成若干個(gè)小任務(wù)(拆到不可再拆時(shí)),再將一個(gè)個(gè)的小任務(wù)運(yùn)算的結(jié)果進(jìn)行 join 匯總。

Fork/Join 框架與線程池的區(qū)別: 采用 “工作竊取”模式(work-stealing):相對(duì)于一般的線程池實(shí)現(xiàn),fork/join框架的優(yōu)勢(shì)體現(xiàn)在對(duì)其中包含的任務(wù)的處理方式上.在一般的線程池中,如果一個(gè)線程正在執(zhí)行的任務(wù)由于某些原因無法繼續(xù)運(yùn)行,那么該線程會(huì)處于等待狀態(tài)。而在fork/join框架實(shí)現(xiàn)中,如果某個(gè)子問題由于等待另外一個(gè)子問題 的完成而無法繼續(xù)運(yùn)行。那么處理該子問題的線程會(huì)主動(dòng)尋找其他尚未運(yùn)行的子問題來執(zhí)行.這種方式減少了線程的等待時(shí)間,提高了性能。
public class TestForkJoinPool { public static void main(String[] args) { Instant start=Instant.now(); ForkJoinPool pool=new ForkJoinPool(); ForkJoinTask<Long> task=new ForkJoinSumCalculate(0L, 50000000000L); Long sum=pool.invoke(task); System.out.println(sum); Instant end=Instant.now(); System.out.println("耗費(fèi)時(shí)間為:"+Duration.between(start, end).toMillis());//耗費(fèi)時(shí)間為:21020 } //一般的方法 @Test public void test1(){ Instant start=Instant.now(); long sum=0L; for(long i=0L;i<=50000000000L;i++){ sum+=i; } System.out.println(sum); Instant end=Instant.now(); System.out.println("耗費(fèi)時(shí)間為:"+Duration.between(start, end).toMillis());//耗費(fèi)時(shí)間為:27040 } //java8 新特性 @Test public void test2(){ Instant start=Instant.now(); Long sum=LongStream.rangeClosed(0L,50000000000L).parallel().reduce(0L, Long::sum); System.out.println(sum); Instant end=Instant.now(); System.out.println("耗費(fèi)時(shí)間為:"+Duration.between(start, end).toMillis());//耗費(fèi)時(shí)間為:14281 }}class ForkJoinSumCalculate extends RecursiveTask<Long>{ private static final long serialVersionUID=-54565646543212315L; private long start; private long end; private static final long THURSHOLD=10000L;//臨界值,小于這個(gè)值就不拆了,直接運(yùn)算 public ForkJoinSumCalculate(long start,long end){ this.start=start; this.end=end; } @Override protected Long compute() { long length=end-start; if(length<=THURSHOLD){ long sum=0L; for(long i=start;i<=end;i++){ sum+=i; } return sum; }else{ //進(jìn)行拆分,同時(shí)壓入線程隊(duì)列 long middle=(start+end)/2; ForkJoinSumCalculate left=new ForkJoinSumCalculate(start, middle); left.fork(); ForkJoinSumCalculate right=new ForkJoinSumCalculate(middle+1, end); right.fork(); return left.join()+right.join(); } }}新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注